@scenarist/core 0.2.1 → 0.3.1
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 +71 -0
- package/dist/domain/log-events.d.ts.map +1 -0
- package/dist/domain/log-events.js +74 -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 +120 -13
- 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 +3 -3
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Logger, LogLevel, LogCategory, LogContext } from "../ports/driven/logger.js";
|
|
2
|
+
/**
|
|
3
|
+
* Output format for ConsoleLogger.
|
|
4
|
+
*/
|
|
5
|
+
export type LogFormat = "pretty" | "json";
|
|
6
|
+
/**
|
|
7
|
+
* Configuration options for ConsoleLogger.
|
|
8
|
+
*/
|
|
9
|
+
export type ConsoleLoggerConfig = {
|
|
10
|
+
readonly level: Exclude<LogLevel, "silent">;
|
|
11
|
+
readonly categories?: ReadonlyArray<LogCategory>;
|
|
12
|
+
readonly format?: LogFormat;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Console logger implementation for development.
|
|
16
|
+
*/
|
|
17
|
+
export declare class ConsoleLogger implements Logger {
|
|
18
|
+
private readonly configuredLevel;
|
|
19
|
+
private readonly configuredCategories;
|
|
20
|
+
private readonly format;
|
|
21
|
+
private readonly testIdColors;
|
|
22
|
+
constructor(config: ConsoleLoggerConfig);
|
|
23
|
+
private getTestIdColor;
|
|
24
|
+
private shouldLog;
|
|
25
|
+
private formatTimestamp;
|
|
26
|
+
private formatData;
|
|
27
|
+
private formatPretty;
|
|
28
|
+
private formatOutput;
|
|
29
|
+
error(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
30
|
+
warn(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
31
|
+
info(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
32
|
+
debug(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
33
|
+
trace(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
34
|
+
isEnabled(level: Exclude<LogLevel, "silent">): boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Factory function for ConsoleLogger.
|
|
38
|
+
*/
|
|
39
|
+
export declare const createConsoleLogger: (config: ConsoleLoggerConfig) => Logger;
|
|
40
|
+
//# sourceMappingURL=console-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console-logger.d.ts","sourceRoot":"","sources":["../../src/adapters/console-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,QAAQ,EACR,WAAW,EACX,UAAU,EACX,MAAM,2BAA2B,CAAC;AA0FnC;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,qBAAa,aAAc,YAAW,MAAM;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA8B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAkC;IACvE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;gBAEnD,MAAM,EAAE,mBAAmB;IAQvC,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,YAAY;IA8BpB,OAAO,CAAC,YAAY;IAoBpB,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;IAQP,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;IAMP,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;IAMP,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;IAQP,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;IAQP,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,OAAO;CAGvD;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,mBAAmB,KAAG,MACvC,CAAC"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Level priority for filtering (lower = less verbose).
|
|
3
|
+
*/
|
|
4
|
+
const LEVEL_PRIORITY = {
|
|
5
|
+
error: 1,
|
|
6
|
+
warn: 2,
|
|
7
|
+
info: 3,
|
|
8
|
+
debug: 4,
|
|
9
|
+
trace: 5,
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Category icons for pretty format.
|
|
13
|
+
*/
|
|
14
|
+
const CATEGORY_ICONS = {
|
|
15
|
+
lifecycle: "🔄",
|
|
16
|
+
scenario: "🎬",
|
|
17
|
+
matching: "🎯",
|
|
18
|
+
sequence: "📊",
|
|
19
|
+
state: "💾",
|
|
20
|
+
template: "📝",
|
|
21
|
+
request: "🌐",
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Level labels for pretty format.
|
|
25
|
+
*/
|
|
26
|
+
const LEVEL_LABELS = {
|
|
27
|
+
error: "ERR",
|
|
28
|
+
warn: "WRN",
|
|
29
|
+
info: "INF",
|
|
30
|
+
debug: "DBG",
|
|
31
|
+
trace: "TRC",
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* ANSI color codes.
|
|
35
|
+
*/
|
|
36
|
+
const COLORS = {
|
|
37
|
+
reset: "\x1b[0m",
|
|
38
|
+
dim: "\x1b[2m",
|
|
39
|
+
red: "\x1b[31m",
|
|
40
|
+
yellow: "\x1b[33m",
|
|
41
|
+
cyan: "\x1b[36m",
|
|
42
|
+
gray: "\x1b[90m",
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Test ID color palette for persistent coloring.
|
|
46
|
+
*/
|
|
47
|
+
const TEST_ID_COLORS = [
|
|
48
|
+
"\x1b[36m", // Cyan
|
|
49
|
+
"\x1b[33m", // Yellow
|
|
50
|
+
"\x1b[35m", // Magenta
|
|
51
|
+
"\x1b[32m", // Green
|
|
52
|
+
"\x1b[34m", // Blue
|
|
53
|
+
"\x1b[91m", // Bright Red
|
|
54
|
+
"\x1b[92m", // Bright Green
|
|
55
|
+
"\x1b[93m", // Bright Yellow
|
|
56
|
+
"\x1b[94m", // Bright Blue
|
|
57
|
+
"\x1b[95m", // Bright Magenta
|
|
58
|
+
"\x1b[96m", // Bright Cyan
|
|
59
|
+
];
|
|
60
|
+
/**
|
|
61
|
+
* Simple hash function for consistent color assignment.
|
|
62
|
+
*/
|
|
63
|
+
const hashString = (str) => {
|
|
64
|
+
let hash = 0;
|
|
65
|
+
for (let i = 0; i < str.length; i++) {
|
|
66
|
+
const char = str.charCodeAt(i);
|
|
67
|
+
hash = (hash << 5) - hash + char;
|
|
68
|
+
hash = hash & hash;
|
|
69
|
+
}
|
|
70
|
+
return Math.abs(hash);
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Level colors for pretty format.
|
|
74
|
+
*/
|
|
75
|
+
const LEVEL_COLORS = {
|
|
76
|
+
error: COLORS.red,
|
|
77
|
+
warn: COLORS.yellow,
|
|
78
|
+
info: COLORS.cyan,
|
|
79
|
+
debug: COLORS.gray,
|
|
80
|
+
trace: COLORS.dim,
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Console logger implementation for development.
|
|
84
|
+
*/
|
|
85
|
+
export class ConsoleLogger {
|
|
86
|
+
configuredLevel;
|
|
87
|
+
configuredCategories;
|
|
88
|
+
format;
|
|
89
|
+
testIdColors = new Map();
|
|
90
|
+
constructor(config) {
|
|
91
|
+
this.configuredLevel = config.level;
|
|
92
|
+
this.configuredCategories = config.categories
|
|
93
|
+
? new Set(config.categories)
|
|
94
|
+
: null;
|
|
95
|
+
this.format = config.format ?? "pretty";
|
|
96
|
+
}
|
|
97
|
+
getTestIdColor(testId) {
|
|
98
|
+
const existingColor = this.testIdColors.get(testId);
|
|
99
|
+
if (existingColor) {
|
|
100
|
+
return existingColor;
|
|
101
|
+
}
|
|
102
|
+
const hash = hashString(testId);
|
|
103
|
+
// colorIndex is always 0 to TEST_ID_COLORS.length-1, so index is always valid
|
|
104
|
+
const colorIndex = hash % TEST_ID_COLORS.length;
|
|
105
|
+
const newColor = TEST_ID_COLORS[colorIndex];
|
|
106
|
+
this.testIdColors.set(testId, newColor);
|
|
107
|
+
return newColor;
|
|
108
|
+
}
|
|
109
|
+
shouldLog(level, category) {
|
|
110
|
+
const levelAllowed = LEVEL_PRIORITY[level] <= LEVEL_PRIORITY[this.configuredLevel];
|
|
111
|
+
const categoryAllowed = this.configuredCategories === null ||
|
|
112
|
+
this.configuredCategories.has(category);
|
|
113
|
+
return levelAllowed && categoryAllowed;
|
|
114
|
+
}
|
|
115
|
+
formatTimestamp() {
|
|
116
|
+
const now = new Date();
|
|
117
|
+
const hours = now.getHours().toString().padStart(2, "0");
|
|
118
|
+
const minutes = now.getMinutes().toString().padStart(2, "0");
|
|
119
|
+
const seconds = now.getSeconds().toString().padStart(2, "0");
|
|
120
|
+
const ms = now.getMilliseconds().toString().padStart(3, "0");
|
|
121
|
+
return `${hours}:${minutes}:${seconds}.${ms}`;
|
|
122
|
+
}
|
|
123
|
+
formatData(data) {
|
|
124
|
+
return Object.entries(data)
|
|
125
|
+
.map(([key, value]) => `${key}=${JSON.stringify(value)}`)
|
|
126
|
+
.join(" ");
|
|
127
|
+
}
|
|
128
|
+
formatPretty(level, category, message, context, data) {
|
|
129
|
+
const timestamp = this.formatTimestamp();
|
|
130
|
+
const levelColor = LEVEL_COLORS[level];
|
|
131
|
+
const levelLabel = LEVEL_LABELS[level];
|
|
132
|
+
const icon = CATEGORY_ICONS[category];
|
|
133
|
+
const testId = context.testId ?? "unknown";
|
|
134
|
+
const testIdColor = this.getTestIdColor(testId);
|
|
135
|
+
const parts = [
|
|
136
|
+
`${COLORS.dim}${timestamp}${COLORS.reset}`,
|
|
137
|
+
`${levelColor}${levelLabel}${COLORS.reset}`,
|
|
138
|
+
`${testIdColor}[${testId}]${COLORS.reset}`,
|
|
139
|
+
`${icon}`,
|
|
140
|
+
category.padEnd(10),
|
|
141
|
+
message,
|
|
142
|
+
];
|
|
143
|
+
if (data && Object.keys(data).length > 0) {
|
|
144
|
+
parts.push(`${COLORS.dim}${this.formatData(data)}${COLORS.reset}`);
|
|
145
|
+
}
|
|
146
|
+
return parts.join(" ");
|
|
147
|
+
}
|
|
148
|
+
formatOutput(level, category, message, context, data) {
|
|
149
|
+
if (this.format === "json") {
|
|
150
|
+
return JSON.stringify({
|
|
151
|
+
timestamp: Date.now(),
|
|
152
|
+
level,
|
|
153
|
+
category,
|
|
154
|
+
message,
|
|
155
|
+
...context,
|
|
156
|
+
...(data ? { data } : {}),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return this.formatPretty(level, category, message, context, data);
|
|
160
|
+
}
|
|
161
|
+
error(category, message, context, data) {
|
|
162
|
+
if (this.shouldLog("error", category)) {
|
|
163
|
+
console.error(this.formatOutput("error", category, message, context, data));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
warn(category, message, context, data) {
|
|
167
|
+
if (this.shouldLog("warn", category)) {
|
|
168
|
+
console.warn(this.formatOutput("warn", category, message, context, data));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
info(category, message, context, data) {
|
|
172
|
+
if (this.shouldLog("info", category)) {
|
|
173
|
+
console.info(this.formatOutput("info", category, message, context, data));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
debug(category, message, context, data) {
|
|
177
|
+
if (this.shouldLog("debug", category)) {
|
|
178
|
+
console.debug(this.formatOutput("debug", category, message, context, data));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
trace(category, message, context, data) {
|
|
182
|
+
if (this.shouldLog("trace", category)) {
|
|
183
|
+
console.debug(this.formatOutput("trace", category, message, context, data));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
isEnabled(level) {
|
|
187
|
+
return LEVEL_PRIORITY[level] <= LEVEL_PRIORITY[this.configuredLevel];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Factory function for ConsoleLogger.
|
|
192
|
+
*/
|
|
193
|
+
export const createConsoleLogger = (config) => new ConsoleLogger(config);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in-memory-state-manager.d.ts","sourceRoot":"","sources":["../../src/adapters/in-memory-state-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAMrE;;;;;;GAMG;AACH,qBAAa,oBAAqB,YAAW,YAAY;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8C;IAEtE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAUzC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAyBtD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI/C,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAgB7D,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"in-memory-state-manager.d.ts","sourceRoot":"","sources":["../../src/adapters/in-memory-state-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAMrE;;;;;;GAMG;AACH,qBAAa,oBAAqB,YAAW,YAAY;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8C;IAEtE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAUzC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAyBtD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI/C,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAgB7D,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,cAAc;IA0CtB,OAAO,CAAC,cAAc;CA6BvB;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B,QAAO,YAE7C,CAAC"}
|
|
@@ -80,6 +80,7 @@ export class InMemoryStateManager {
|
|
|
80
80
|
});
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
|
+
// eslint-disable-next-line security/detect-object-injection -- Guarded by isDangerousKey and Object.hasOwn
|
|
83
84
|
const existingValue = Object.hasOwn(obj, key) ? obj[key] : undefined;
|
|
84
85
|
if (typeof existingValue !== "object" ||
|
|
85
86
|
existingValue === null ||
|
|
@@ -91,6 +92,7 @@ export class InMemoryStateManager {
|
|
|
91
92
|
configurable: true,
|
|
92
93
|
});
|
|
93
94
|
}
|
|
95
|
+
// eslint-disable-next-line security/detect-object-injection -- Guarded by isDangerousKey, Object.hasOwn, and Object.defineProperty
|
|
94
96
|
const nested = obj[key];
|
|
95
97
|
this.setNestedValue(nested, path.slice(1), value);
|
|
96
98
|
}
|
|
@@ -104,6 +106,7 @@ export class InMemoryStateManager {
|
|
|
104
106
|
if (!Object.hasOwn(obj, key)) {
|
|
105
107
|
return undefined;
|
|
106
108
|
}
|
|
109
|
+
// eslint-disable-next-line security/detect-object-injection -- Guarded by isDangerousKey and Object.hasOwn
|
|
107
110
|
const value = obj[key];
|
|
108
111
|
if (path.length === 1) {
|
|
109
112
|
return value;
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -2,4 +2,6 @@ export { InMemoryScenarioRegistry } from "./in-memory-registry.js";
|
|
|
2
2
|
export { InMemoryScenarioStore } from "./in-memory-store.js";
|
|
3
3
|
export { InMemorySequenceTracker, createInMemorySequenceTracker, } from "./in-memory-sequence-tracker.js";
|
|
4
4
|
export { InMemoryStateManager, createInMemoryStateManager, } from "./in-memory-state-manager.js";
|
|
5
|
+
export { NoOpLogger, noOpLogger, createNoOpLogger } from "./noop-logger.js";
|
|
6
|
+
export { ConsoleLogger, createConsoleLogger, type ConsoleLoggerConfig, type LogFormat, } from "./console-logger.js";
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EACL,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EACL,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,SAAS,GACf,MAAM,qBAAqB,CAAC"}
|
package/dist/adapters/index.js
CHANGED
|
@@ -2,3 +2,5 @@ export { InMemoryScenarioRegistry } from "./in-memory-registry.js";
|
|
|
2
2
|
export { InMemoryScenarioStore } from "./in-memory-store.js";
|
|
3
3
|
export { InMemorySequenceTracker, createInMemorySequenceTracker, } from "./in-memory-sequence-tracker.js";
|
|
4
4
|
export { InMemoryStateManager, createInMemoryStateManager, } from "./in-memory-state-manager.js";
|
|
5
|
+
export { NoOpLogger, noOpLogger, createNoOpLogger } from "./noop-logger.js";
|
|
6
|
+
export { ConsoleLogger, createConsoleLogger, } from "./console-logger.js";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Logger } from "../ports/driven/logger.js";
|
|
2
|
+
/**
|
|
3
|
+
* No-operation logger that discards all log calls.
|
|
4
|
+
*
|
|
5
|
+
* Used when logging is disabled for zero overhead.
|
|
6
|
+
* All methods are empty - V8 will inline and eliminate them.
|
|
7
|
+
*/
|
|
8
|
+
export declare class NoOpLogger implements Logger {
|
|
9
|
+
error(): void;
|
|
10
|
+
warn(): void;
|
|
11
|
+
info(): void;
|
|
12
|
+
debug(): void;
|
|
13
|
+
trace(): void;
|
|
14
|
+
isEnabled(): boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Singleton NoOpLogger instance.
|
|
18
|
+
* Prevents unnecessary allocations.
|
|
19
|
+
*/
|
|
20
|
+
export declare const noOpLogger: Logger;
|
|
21
|
+
/**
|
|
22
|
+
* Factory function for NoOpLogger.
|
|
23
|
+
* Returns the singleton instance.
|
|
24
|
+
*/
|
|
25
|
+
export declare const createNoOpLogger: () => Logger;
|
|
26
|
+
//# sourceMappingURL=noop-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noop-logger.d.ts","sourceRoot":"","sources":["../../src/adapters/noop-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAExD;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,MAAM;IACvC,KAAK,IAAI,IAAI;IACb,IAAI,IAAI,IAAI;IACZ,IAAI,IAAI,IAAI;IACZ,KAAK,IAAI,IAAI;IACb,KAAK,IAAI,IAAI;IACb,SAAS,IAAI,OAAO;CAGrB;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,MAAyB,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,QAAO,MAAoB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* No-operation logger that discards all log calls.
|
|
3
|
+
*
|
|
4
|
+
* Used when logging is disabled for zero overhead.
|
|
5
|
+
* All methods are empty - V8 will inline and eliminate them.
|
|
6
|
+
*/
|
|
7
|
+
export class NoOpLogger {
|
|
8
|
+
error() { }
|
|
9
|
+
warn() { }
|
|
10
|
+
info() { }
|
|
11
|
+
debug() { }
|
|
12
|
+
trace() { }
|
|
13
|
+
isEnabled() {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Singleton NoOpLogger instance.
|
|
19
|
+
* Prevents unnecessary allocations.
|
|
20
|
+
*/
|
|
21
|
+
export const noOpLogger = new NoOpLogger();
|
|
22
|
+
/**
|
|
23
|
+
* Factory function for NoOpLogger.
|
|
24
|
+
* Returns the singleton instance.
|
|
25
|
+
*/
|
|
26
|
+
export const createNoOpLogger = () => noOpLogger;
|
|
@@ -3,6 +3,7 @@ import type { ScenarioRegistry } from "../ports/driven/scenario-registry.js";
|
|
|
3
3
|
import type { ScenarioStore } from "../ports/driven/scenario-store.js";
|
|
4
4
|
import type { StateManager } from "../ports/driven/state-manager.js";
|
|
5
5
|
import type { SequenceTracker } from "../ports/driven/sequence-tracker.js";
|
|
6
|
+
import type { Logger } from "../ports/driven/logger.js";
|
|
6
7
|
/**
|
|
7
8
|
* Base configuration options that all framework adapters must support.
|
|
8
9
|
*
|
|
@@ -49,6 +50,23 @@ export type BaseAdapterOptions<T extends ScenaristScenarios = ScenaristScenarios
|
|
|
49
50
|
* If not provided, an in-memory sequence tracker will be used.
|
|
50
51
|
*/
|
|
51
52
|
readonly sequenceTracker?: SequenceTracker;
|
|
53
|
+
/**
|
|
54
|
+
* Logger implementation for debugging and observability.
|
|
55
|
+
*
|
|
56
|
+
* If not provided, NoOpLogger will be used (silent).
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* import { createConsoleLogger } from '@scenarist/express-adapter';
|
|
61
|
+
*
|
|
62
|
+
* const scenarist = createScenarist({
|
|
63
|
+
* enabled: true,
|
|
64
|
+
* scenarios,
|
|
65
|
+
* logger: createConsoleLogger({ level: 'debug' }),
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
readonly logger?: Logger;
|
|
52
70
|
};
|
|
53
71
|
/**
|
|
54
72
|
* The contract that all Scenarist adapters must satisfy.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-adapter.d.ts","sourceRoot":"","sources":["../../src/contracts/framework-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"framework-adapter.d.ts","sourceRoot":"","sources":["../../src/contracts/framework-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAC3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,kBAAkB,CAC5B,CAAC,SAAS,kBAAkB,GAAG,kBAAkB,IAC/C,oBAAoB,CAAC,CAAC,CAAC,GAAG;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAErC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAE/B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAErC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;IAE3C;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,gBAAgB,CAC1B,WAAW,GAAG,OAAO,EACrB,UAAU,SAAS,kBAAkB,GAAG,kBAAkB,IACxD;IACF;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IAEjC;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IAEjC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,CACvB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC,KAChC,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAElC;;OAEG;IACH,QAAQ,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,cAAc,GAAG,SAAS,CAAC;IAE3E;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,CACxB,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC,KAChC,iBAAiB,GAAG,SAAS,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAE/D;;OAEG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjD;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAE3B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-builder.d.ts","sourceRoot":"","sources":["../../src/domain/config-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"config-builder.d.ts","sourceRoot":"","sources":["../../src/domain/config-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAEnB,MAAM,mBAAmB,CAAC;AAa3B;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,kBAAkB,EACtD,OAAO,oBAAoB,CAAC,CAAC,CAAC,KAC7B,eAiBF,CAAC"}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { ScenariosObjectSchema } from "../schemas/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Default error behaviors - strict by default.
|
|
4
|
+
* All errors throw to ensure tests fail clearly when something goes wrong.
|
|
5
|
+
*/
|
|
6
|
+
const DEFAULT_ERROR_BEHAVIORS = {
|
|
7
|
+
onNoMockFound: "throw",
|
|
8
|
+
onSequenceExhausted: "throw",
|
|
9
|
+
onMissingTestId: "throw",
|
|
10
|
+
};
|
|
2
11
|
/**
|
|
3
12
|
* Build a complete config from partial user input.
|
|
4
13
|
* Applies sensible defaults for missing values.
|
|
@@ -16,5 +25,9 @@ export const buildConfig = (input) => {
|
|
|
16
25
|
getScenario: input.endpoints?.getScenario ?? "/__scenario__",
|
|
17
26
|
},
|
|
18
27
|
defaultTestId: input.defaultTestId ?? "default-test",
|
|
28
|
+
errorBehaviors: {
|
|
29
|
+
...DEFAULT_ERROR_BEHAVIORS,
|
|
30
|
+
...input.errorBehaviors,
|
|
31
|
+
},
|
|
19
32
|
};
|
|
20
33
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deep-equals.d.ts","sourceRoot":"","sources":["../../src/domain/deep-equals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,OAAO,EAAE,GAAG,OAAO,KAAG,
|
|
1
|
+
{"version":3,"file":"deep-equals.d.ts","sourceRoot":"","sources":["../../src/domain/deep-equals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,OAAO,EAAE,GAAG,OAAO,KAAG,OAoEnD,CAAC"}
|
|
@@ -31,6 +31,7 @@ export const deepEquals = (a, b) => {
|
|
|
31
31
|
return false;
|
|
32
32
|
}
|
|
33
33
|
for (let i = 0; i < a.length; i++) {
|
|
34
|
+
// eslint-disable-next-line security/detect-object-injection -- Index bounded by array length check
|
|
34
35
|
if (!deepEquals(a[i], b[i])) {
|
|
35
36
|
return false;
|
|
36
37
|
}
|
|
@@ -52,6 +53,7 @@ export const deepEquals = (a, b) => {
|
|
|
52
53
|
if (!(key in b)) {
|
|
53
54
|
return false;
|
|
54
55
|
}
|
|
56
|
+
// eslint-disable-next-line security/detect-object-injection -- Keys from Object.keys (own properties only)
|
|
55
57
|
if (!deepEquals(a[key], b[key])) {
|
|
56
58
|
return false;
|
|
57
59
|
}
|
package/dist/domain/index.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export { matchesRegex } from "./regex-matching.js";
|
|
|
5
5
|
export { createStateConditionEvaluator, type StateConditionEvaluator, } from "./state-condition-evaluator.js";
|
|
6
6
|
export { createStateResponseResolver, type StateResponseResolver, } from "./state-response-resolver.js";
|
|
7
7
|
export { deepEquals } from "./deep-equals.js";
|
|
8
|
+
export { LogCategories, LogEvents, type LogEvent } from "./log-events.js";
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,6BAA6B,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,2BAA2B,EAC3B,KAAK,qBAAqB,GAC3B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,6BAA6B,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,2BAA2B,EAC3B,KAAK,qBAAqB,GAC3B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/domain/index.js
CHANGED
|
@@ -5,3 +5,4 @@ export { matchesRegex } from "./regex-matching.js";
|
|
|
5
5
|
export { createStateConditionEvaluator, } from "./state-condition-evaluator.js";
|
|
6
6
|
export { createStateResponseResolver, } from "./state-response-resolver.js";
|
|
7
7
|
export { deepEquals } from "./deep-equals.js";
|
|
8
|
+
export { LogCategories, LogEvents } from "./log-events.js";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log event constants for consistent and discoverable logging.
|
|
3
|
+
*
|
|
4
|
+
* Using constants ensures:
|
|
5
|
+
* - TypeScript type safety for event names
|
|
6
|
+
* - Discoverability via IDE autocomplete
|
|
7
|
+
* - Consistent naming across the codebase
|
|
8
|
+
* - Easy refactoring of event names
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Log categories group related events.
|
|
12
|
+
*
|
|
13
|
+
* The values here match the LogCategory type from ports/driven/logger.ts.
|
|
14
|
+
* Using these constants instead of string literals provides:
|
|
15
|
+
* - IDE autocomplete
|
|
16
|
+
* - Refactoring safety
|
|
17
|
+
* - Single source of truth for category names
|
|
18
|
+
*/
|
|
19
|
+
export declare const LogCategories: {
|
|
20
|
+
/** Scenario lifecycle events (registration, switching, clearing) */
|
|
21
|
+
readonly SCENARIO: "scenario";
|
|
22
|
+
/** Mock matching and selection events */
|
|
23
|
+
readonly MATCHING: "matching";
|
|
24
|
+
/** State capture and injection events */
|
|
25
|
+
readonly STATE: "state";
|
|
26
|
+
/** Sequence progression events */
|
|
27
|
+
readonly SEQUENCE: "sequence";
|
|
28
|
+
/** Request handling events */
|
|
29
|
+
readonly REQUEST: "request";
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Log event names for structured logging.
|
|
33
|
+
*/
|
|
34
|
+
export declare const LogEvents: {
|
|
35
|
+
/** Scenario successfully registered */
|
|
36
|
+
readonly SCENARIO_REGISTERED: "scenario_registered";
|
|
37
|
+
/** Attempted to switch to non-existent scenario */
|
|
38
|
+
readonly SCENARIO_NOT_FOUND: "scenario_not_found";
|
|
39
|
+
/** Scenario switched for a test */
|
|
40
|
+
readonly SCENARIO_SWITCHED: "scenario_switched";
|
|
41
|
+
/** Scenario cleared for a test */
|
|
42
|
+
readonly SCENARIO_CLEARED: "scenario_cleared";
|
|
43
|
+
/** Candidate mocks found for evaluation */
|
|
44
|
+
readonly MOCK_CANDIDATES_FOUND: "mock_candidates_found";
|
|
45
|
+
/** Mock evaluated against match criteria */
|
|
46
|
+
readonly MOCK_MATCH_EVALUATED: "mock_match_evaluated";
|
|
47
|
+
/** Mock selected to handle request */
|
|
48
|
+
readonly MOCK_SELECTED: "mock_selected";
|
|
49
|
+
/** No mock matched the request */
|
|
50
|
+
readonly MOCK_NO_MATCH: "mock_no_match";
|
|
51
|
+
/** State captured from response */
|
|
52
|
+
readonly STATE_CAPTURED: "state_captured";
|
|
53
|
+
/** State injected into response */
|
|
54
|
+
readonly STATE_INJECTED: "state_injected";
|
|
55
|
+
/** State set via afterResponse.setState */
|
|
56
|
+
readonly STATE_SET: "state_set";
|
|
57
|
+
/** State response resolved (condition matched or default) */
|
|
58
|
+
readonly STATE_RESPONSE_RESOLVED: "state_response_resolved";
|
|
59
|
+
/** Sequence advanced to next response */
|
|
60
|
+
readonly SEQUENCE_ADVANCED: "sequence_advanced";
|
|
61
|
+
/** Sequence exhausted all responses */
|
|
62
|
+
readonly SEQUENCE_EXHAUSTED: "sequence_exhausted";
|
|
63
|
+
/** Unhandled error in request handler */
|
|
64
|
+
readonly HANDLER_ERROR: "handler_error";
|
|
65
|
+
/** Validation error in scenario definition */
|
|
66
|
+
readonly VALIDATION_ERROR: "validation_error";
|
|
67
|
+
/** Request missing test ID header */
|
|
68
|
+
readonly MISSING_TEST_ID: "missing_test_id";
|
|
69
|
+
};
|
|
70
|
+
export type LogEvent = (typeof LogEvents)[keyof typeof LogEvents];
|
|
71
|
+
//# sourceMappingURL=log-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-events.d.ts","sourceRoot":"","sources":["../../src/domain/log-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa;IACxB,oEAAoE;;IAEpE,yCAAyC;;IAEzC,yCAAyC;;IAEzC,kCAAkC;;IAElC,8BAA8B;;CAEtB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,SAAS;IAEpB,uCAAuC;;IAEvC,mDAAmD;;IAEnD,mCAAmC;;IAEnC,kCAAkC;;IAIlC,2CAA2C;;IAE3C,4CAA4C;;IAE5C,sCAAsC;;IAEtC,kCAAkC;;IAIlC,mCAAmC;;IAEnC,mCAAmC;;IAEnC,2CAA2C;;IAE3C,6DAA6D;;IAI7D,yCAAyC;;IAEzC,uCAAuC;;IAIvC,yCAAyC;;IAEzC,8CAA8C;;IAE9C,qCAAqC;;CAE7B,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log event constants for consistent and discoverable logging.
|
|
3
|
+
*
|
|
4
|
+
* Using constants ensures:
|
|
5
|
+
* - TypeScript type safety for event names
|
|
6
|
+
* - Discoverability via IDE autocomplete
|
|
7
|
+
* - Consistent naming across the codebase
|
|
8
|
+
* - Easy refactoring of event names
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Log categories group related events.
|
|
12
|
+
*
|
|
13
|
+
* The values here match the LogCategory type from ports/driven/logger.ts.
|
|
14
|
+
* Using these constants instead of string literals provides:
|
|
15
|
+
* - IDE autocomplete
|
|
16
|
+
* - Refactoring safety
|
|
17
|
+
* - Single source of truth for category names
|
|
18
|
+
*/
|
|
19
|
+
export const LogCategories = {
|
|
20
|
+
/** Scenario lifecycle events (registration, switching, clearing) */
|
|
21
|
+
SCENARIO: "scenario",
|
|
22
|
+
/** Mock matching and selection events */
|
|
23
|
+
MATCHING: "matching",
|
|
24
|
+
/** State capture and injection events */
|
|
25
|
+
STATE: "state",
|
|
26
|
+
/** Sequence progression events */
|
|
27
|
+
SEQUENCE: "sequence",
|
|
28
|
+
/** Request handling events */
|
|
29
|
+
REQUEST: "request",
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Log event names for structured logging.
|
|
33
|
+
*/
|
|
34
|
+
export const LogEvents = {
|
|
35
|
+
// Scenario lifecycle
|
|
36
|
+
/** Scenario successfully registered */
|
|
37
|
+
SCENARIO_REGISTERED: "scenario_registered",
|
|
38
|
+
/** Attempted to switch to non-existent scenario */
|
|
39
|
+
SCENARIO_NOT_FOUND: "scenario_not_found",
|
|
40
|
+
/** Scenario switched for a test */
|
|
41
|
+
SCENARIO_SWITCHED: "scenario_switched",
|
|
42
|
+
/** Scenario cleared for a test */
|
|
43
|
+
SCENARIO_CLEARED: "scenario_cleared",
|
|
44
|
+
// Mock matching
|
|
45
|
+
/** Candidate mocks found for evaluation */
|
|
46
|
+
MOCK_CANDIDATES_FOUND: "mock_candidates_found",
|
|
47
|
+
/** Mock evaluated against match criteria */
|
|
48
|
+
MOCK_MATCH_EVALUATED: "mock_match_evaluated",
|
|
49
|
+
/** Mock selected to handle request */
|
|
50
|
+
MOCK_SELECTED: "mock_selected",
|
|
51
|
+
/** No mock matched the request */
|
|
52
|
+
MOCK_NO_MATCH: "mock_no_match",
|
|
53
|
+
// State management
|
|
54
|
+
/** State captured from response */
|
|
55
|
+
STATE_CAPTURED: "state_captured",
|
|
56
|
+
/** State injected into response */
|
|
57
|
+
STATE_INJECTED: "state_injected",
|
|
58
|
+
/** State set via afterResponse.setState */
|
|
59
|
+
STATE_SET: "state_set",
|
|
60
|
+
/** State response resolved (condition matched or default) */
|
|
61
|
+
STATE_RESPONSE_RESOLVED: "state_response_resolved",
|
|
62
|
+
// Sequence progression
|
|
63
|
+
/** Sequence advanced to next response */
|
|
64
|
+
SEQUENCE_ADVANCED: "sequence_advanced",
|
|
65
|
+
/** Sequence exhausted all responses */
|
|
66
|
+
SEQUENCE_EXHAUSTED: "sequence_exhausted",
|
|
67
|
+
// Error events
|
|
68
|
+
/** Unhandled error in request handler */
|
|
69
|
+
HANDLER_ERROR: "handler_error",
|
|
70
|
+
/** Validation error in scenario definition */
|
|
71
|
+
VALIDATION_ERROR: "validation_error",
|
|
72
|
+
/** Request missing test ID header */
|
|
73
|
+
MISSING_TEST_ID: "missing_test_id",
|
|
74
|
+
};
|
|
@@ -69,6 +69,7 @@ const traversePath = (obj, path) => {
|
|
|
69
69
|
return undefined;
|
|
70
70
|
}
|
|
71
71
|
const record = obj;
|
|
72
|
+
// eslint-disable-next-line security/detect-object-injection -- Key validated by Object.hasOwn and isDangerousKey guard
|
|
72
73
|
const value = record[key];
|
|
73
74
|
// Recursively traverse remaining path
|
|
74
75
|
return traversePath(value, path.slice(1));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"regex-matching.d.ts","sourceRoot":"","sources":["../../src/domain/regex-matching.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,EACb,SAAS,eAAe,KACvB,
|
|
1
|
+
{"version":3,"file":"regex-matching.d.ts","sourceRoot":"","sources":["../../src/domain/regex-matching.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,EACb,SAAS,eAAe,KACvB,OASF,CAAC"}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
export const matchesRegex = (value, pattern) => {
|
|
19
19
|
try {
|
|
20
|
+
// eslint-disable-next-line security/detect-non-literal-regexp -- Pattern validated at trust boundary (schema uses redos-detector)
|
|
20
21
|
const regex = new RegExp(pattern.source, pattern.flags);
|
|
21
22
|
return regex.test(value);
|
|
22
23
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { ResponseSelector, SequenceTracker, StateManager } from "../ports/index.js";
|
|
1
|
+
import type { ResponseSelector, SequenceTracker, StateManager, Logger } from "../ports/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Options for creating a response selector.
|
|
4
4
|
*/
|
|
5
5
|
type CreateResponseSelectorOptions = {
|
|
6
6
|
sequenceTracker?: SequenceTracker;
|
|
7
7
|
stateManager?: StateManager;
|
|
8
|
+
logger?: Logger;
|
|
8
9
|
};
|
|
9
10
|
/**
|
|
10
11
|
* Creates a response selector domain service.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-selector.d.ts","sourceRoot":"","sources":["../../src/domain/response-selector.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,
|
|
1
|
+
{"version":3,"file":"response-selector.d.ts","sourceRoot":"","sources":["../../src/domain/response-selector.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,MAAM,EACP,MAAM,mBAAmB,CAAC;AAiB3B;;GAEG;AACH,KAAK,6BAA6B,GAAG;IACnC,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GACjC,UAAS,6BAAkC,KAC1C,gBAuQF,CAAC"}
|