@scenarist/core 0.0.1 → 0.1.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.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +755 -28
  3. package/dist/adapters/in-memory-registry.d.ts +18 -0
  4. package/dist/adapters/in-memory-registry.d.ts.map +1 -0
  5. package/dist/adapters/in-memory-registry.js +25 -0
  6. package/dist/adapters/in-memory-sequence-tracker.d.ts +28 -0
  7. package/dist/adapters/in-memory-sequence-tracker.d.ts.map +1 -0
  8. package/dist/adapters/in-memory-sequence-tracker.js +82 -0
  9. package/dist/adapters/in-memory-state-manager.d.ts +24 -0
  10. package/dist/adapters/in-memory-state-manager.d.ts.map +1 -0
  11. package/dist/adapters/in-memory-state-manager.js +81 -0
  12. package/dist/adapters/in-memory-store.d.ts +18 -0
  13. package/dist/adapters/in-memory-store.d.ts.map +1 -0
  14. package/dist/adapters/in-memory-store.js +25 -0
  15. package/dist/adapters/index.d.ts +5 -0
  16. package/dist/adapters/index.d.ts.map +1 -0
  17. package/dist/adapters/index.js +4 -0
  18. package/dist/constants/headers.d.ts +10 -0
  19. package/dist/constants/headers.d.ts.map +1 -0
  20. package/dist/constants/headers.js +9 -0
  21. package/dist/constants/index.d.ts +2 -0
  22. package/dist/constants/index.d.ts.map +1 -0
  23. package/dist/constants/index.js +1 -0
  24. package/dist/contracts/framework-adapter.d.ts +118 -0
  25. package/dist/contracts/framework-adapter.d.ts.map +1 -0
  26. package/dist/contracts/framework-adapter.js +1 -0
  27. package/dist/contracts/index.d.ts +2 -0
  28. package/dist/contracts/index.d.ts.map +1 -0
  29. package/dist/contracts/index.js +1 -0
  30. package/dist/domain/config-builder.d.ts +9 -0
  31. package/dist/domain/config-builder.d.ts.map +1 -0
  32. package/dist/domain/config-builder.js +20 -0
  33. package/dist/domain/index.d.ts +5 -0
  34. package/dist/domain/index.d.ts.map +1 -0
  35. package/dist/domain/index.js +4 -0
  36. package/dist/domain/path-extraction.d.ts +17 -0
  37. package/dist/domain/path-extraction.d.ts.map +1 -0
  38. package/dist/domain/path-extraction.js +60 -0
  39. package/dist/domain/regex-matching.d.ts +20 -0
  40. package/dist/domain/regex-matching.d.ts.map +1 -0
  41. package/dist/domain/regex-matching.js +27 -0
  42. package/dist/domain/response-selector.d.ts +22 -0
  43. package/dist/domain/response-selector.d.ts.map +1 -0
  44. package/dist/domain/response-selector.js +337 -0
  45. package/dist/domain/scenario-manager.d.ts +20 -0
  46. package/dist/domain/scenario-manager.d.ts.map +1 -0
  47. package/dist/domain/scenario-manager.js +90 -0
  48. package/dist/domain/template-replacement.d.ts +11 -0
  49. package/dist/domain/template-replacement.d.ts.map +1 -0
  50. package/dist/domain/template-replacement.js +94 -0
  51. package/dist/index.d.ts +8 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +8 -0
  54. package/dist/ports/driven/request-context.d.ts +43 -0
  55. package/dist/ports/driven/request-context.d.ts.map +1 -0
  56. package/dist/ports/driven/request-context.js +1 -0
  57. package/dist/ports/driven/response-selector.d.ts +34 -0
  58. package/dist/ports/driven/response-selector.d.ts.map +1 -0
  59. package/dist/ports/driven/response-selector.js +9 -0
  60. package/dist/ports/driven/scenario-registry.d.ts +46 -0
  61. package/dist/ports/driven/scenario-registry.d.ts.map +1 -0
  62. package/dist/ports/driven/scenario-registry.js +1 -0
  63. package/dist/ports/driven/scenario-store.d.ts +33 -0
  64. package/dist/ports/driven/scenario-store.d.ts.map +1 -0
  65. package/dist/ports/driven/scenario-store.js +1 -0
  66. package/dist/ports/driven/sequence-tracker.d.ts +49 -0
  67. package/dist/ports/driven/sequence-tracker.d.ts.map +1 -0
  68. package/dist/ports/driven/sequence-tracker.js +1 -0
  69. package/dist/ports/driven/state-manager.d.ts +56 -0
  70. package/dist/ports/driven/state-manager.d.ts.map +1 -0
  71. package/dist/ports/driven/state-manager.js +1 -0
  72. package/dist/ports/driving/scenario-manager.d.ts +99 -0
  73. package/dist/ports/driving/scenario-manager.d.ts.map +1 -0
  74. package/dist/ports/driving/scenario-manager.js +1 -0
  75. package/dist/ports/index.d.ts +8 -0
  76. package/dist/ports/index.d.ts.map +1 -0
  77. package/dist/ports/index.js +1 -0
  78. package/dist/schemas/index.d.ts +18 -0
  79. package/dist/schemas/index.d.ts.map +1 -0
  80. package/dist/schemas/index.js +17 -0
  81. package/dist/schemas/match-criteria.d.ts +27 -0
  82. package/dist/schemas/match-criteria.d.ts.map +1 -0
  83. package/dist/schemas/match-criteria.js +71 -0
  84. package/dist/schemas/scenario-definition.d.ts +276 -0
  85. package/dist/schemas/scenario-definition.d.ts.map +1 -0
  86. package/dist/schemas/scenario-definition.js +78 -0
  87. package/dist/schemas/scenario-requests.d.ts +33 -0
  88. package/dist/schemas/scenario-requests.d.ts.map +1 -0
  89. package/dist/schemas/scenario-requests.js +29 -0
  90. package/dist/schemas/scenarios-object.d.ts +91 -0
  91. package/dist/schemas/scenarios-object.d.ts.map +1 -0
  92. package/dist/schemas/scenarios-object.js +17 -0
  93. package/dist/types/config.d.ts +70 -0
  94. package/dist/types/config.d.ts.map +1 -0
  95. package/dist/types/config.js +1 -0
  96. package/dist/types/index.d.ts +4 -0
  97. package/dist/types/index.d.ts.map +1 -0
  98. package/dist/types/index.js +1 -0
  99. package/dist/types/scenario.d.ts +141 -0
  100. package/dist/types/scenario.d.ts.map +1 -0
  101. package/dist/types/scenario.js +1 -0
  102. package/package.json +67 -7
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Secondary port for extracting context from HTTP requests.
3
+ * Framework adapters implement this to provide test ID extraction.
4
+ *
5
+ * **Implementation Pattern:**
6
+ * Implementations should accept ScenaristConfig to determine which headers
7
+ * to read and what defaults to apply.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { SCENARIST_TEST_ID_HEADER } from '@scenarist/core';
12
+ *
13
+ * class ExpressRequestContext implements RequestContext {
14
+ * constructor(
15
+ * private readonly req: Request,
16
+ * private readonly defaultTestId: string
17
+ * ) {}
18
+ *
19
+ * getTestId(): string {
20
+ * const header = this.req.headers[SCENARIST_TEST_ID_HEADER];
21
+ * return typeof header === 'string' ? header : this.defaultTestId;
22
+ * }
23
+ * }
24
+ * ```
25
+ */
26
+ export interface RequestContext {
27
+ /**
28
+ * Extract the test ID from the request.
29
+ * This enables test isolation.
30
+ */
31
+ getTestId(): string;
32
+ /**
33
+ * Get all request headers.
34
+ * Useful for debugging and logging.
35
+ */
36
+ getHeaders(): Record<string, string | string[] | undefined>;
37
+ /**
38
+ * Get the request hostname.
39
+ * Used to determine passthrough behavior.
40
+ */
41
+ getHostname(): string;
42
+ }
43
+ //# sourceMappingURL=request-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../src/ports/driven/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,SAAS,IAAI,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IAE5D;;;OAGG;IACH,WAAW,IAAI,MAAM,CAAC;CACvB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ import type { ScenaristMockWithParams, ScenaristResponse, HttpRequestContext, ScenaristResult } from "../../types/index.js";
2
+ /**
3
+ * Error type for response selection failures.
4
+ */
5
+ export declare class ResponseSelectionError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ /**
9
+ * Secondary port for response selection.
10
+ * Determines which mock response to return based on request content.
11
+ *
12
+ * Phase 1 (Current): Stateless matching on body/headers/query
13
+ * Phase 2 (Future): Sequence tracking (first call, second call, etc.)
14
+ * Phase 3 (Future): Stateful responses (increment counters, etc.)
15
+ *
16
+ * The interface is defined as a port to allow:
17
+ * - Default implementation: Stateless content matching (createResponseSelector)
18
+ * - Sequence-aware implementation: Track call counts per mock
19
+ * - State-aware implementation: Maintain state across requests
20
+ * - Test doubles: Mock response selection for adapter tests
21
+ */
22
+ export interface ResponseSelector {
23
+ /**
24
+ * Select a response from candidate mocks based on request content.
25
+ *
26
+ * @param testId - Test ID for sequence/state tracking
27
+ * @param scenarioId - Scenario ID for sequence/state tracking
28
+ * @param context - Request context (method, url, body, headers, query)
29
+ * @param mocks - Candidate mocks with extracted params (already filtered by URL/method)
30
+ * @returns ScenaristResult with selected ScenaristResponse or error if no match found
31
+ */
32
+ selectResponse(testId: string, scenarioId: string, context: HttpRequestContext, mocks: ReadonlyArray<ScenaristMockWithParams>): ScenaristResult<ScenaristResponse, ResponseSelectionError>;
33
+ }
34
+ //# sourceMappingURL=response-selector.d.ts.map
@@ -0,0 +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;AAE9B;;GAEG;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,sBAAsB,CAAC,CAAC;CAC/D"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Error type for response selection failures.
3
+ */
4
+ export class ResponseSelectionError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "ResponseSelectionError";
8
+ }
9
+ }
@@ -0,0 +1,46 @@
1
+ import type { ScenaristScenario } from '../../types/index.js';
2
+ /**
3
+ * Secondary port for scenario registry.
4
+ * Manages the catalog of available scenarios.
5
+ *
6
+ * This is separate from ScenarioStore to maintain architectural purity:
7
+ * - ScenarioRegistry: what scenarios exist (the catalog)
8
+ * - ScenarioStore: which scenario each test is using (active state)
9
+ *
10
+ * ScenarioDefinitions are serializable, enabling:
11
+ * - InMemoryScenarioRegistry: Map-based registry (default, fastest)
12
+ * - RedisScenarioRegistry: Distributed scenarios across processes
13
+ * - FileSystemScenarioRegistry: Load scenarios from JSON/YAML files
14
+ * - RemoteScenarioRegistry: Fetch scenarios from REST API
15
+ * - DatabaseScenarioRegistry: Store scenarios in PostgreSQL/MongoDB
16
+ *
17
+ * At runtime, ScenaristMocks are converted to MSW HttpHandlers.
18
+ */
19
+ export interface ScenarioRegistry {
20
+ /**
21
+ * Register a scenario definition.
22
+ * The definition.id is used as the unique identifier.
23
+ * Makes the scenario available for use.
24
+ */
25
+ register(definition: ScenaristScenario): void;
26
+ /**
27
+ * Retrieve a registered scenario definition by ID.
28
+ * Returns undefined if scenario not found.
29
+ */
30
+ get(id: string): ScenaristScenario | undefined;
31
+ /**
32
+ * Check if a scenario ID is registered.
33
+ */
34
+ has(id: string): boolean;
35
+ /**
36
+ * List all registered scenario definitions.
37
+ * Useful for debugging, dev tools, and scenario discovery.
38
+ */
39
+ list(): ReadonlyArray<ScenaristScenario>;
40
+ /**
41
+ * Remove a scenario from the registry.
42
+ * Does not affect already-active scenarios in the store.
43
+ */
44
+ unregister(id: string): void;
45
+ }
46
+ //# sourceMappingURL=scenario-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-registry.d.ts","sourceRoot":"","sources":["../../../src/ports/driven/scenario-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAE9C;;;OAGG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAAC;IAE/C;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAEzB;;;OAGG;IACH,IAAI,IAAI,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAEzC;;;OAGG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import type { ActiveScenario } from '../../types/index.js';
2
+ /**
3
+ * Secondary port for scenario storage.
4
+ * Implementations determine where active scenarios are stored.
5
+ *
6
+ * Examples:
7
+ * - InMemoryScenarioStore: Map-based storage (single process)
8
+ * - RedisScenarioStore: Redis-based storage (distributed tests)
9
+ */
10
+ export interface ScenarioStore {
11
+ /**
12
+ * Store an active scenario for a test ID.
13
+ */
14
+ set(testId: string, scenario: ActiveScenario): void;
15
+ /**
16
+ * Retrieve an active scenario for a test ID.
17
+ */
18
+ get(testId: string): ActiveScenario | undefined;
19
+ /**
20
+ * Check if a test ID has an active scenario.
21
+ */
22
+ has(testId: string): boolean;
23
+ /**
24
+ * Remove the active scenario for a test ID.
25
+ */
26
+ delete(testId: string): void;
27
+ /**
28
+ * Clear all active scenarios.
29
+ * Use with caution - affects all test IDs.
30
+ */
31
+ clear(): void;
32
+ }
33
+ //# sourceMappingURL=scenario-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-store.d.ts","sourceRoot":"","sources":["../../../src/ports/driven/scenario-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IAEpD;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IAEhD;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAE7B;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B;;;OAGG;IACH,KAAK,IAAI,IAAI,CAAC;CACf"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Sequence position state for a specific mock.
3
+ */
4
+ export type SequencePosition = {
5
+ readonly position: number;
6
+ readonly exhausted: boolean;
7
+ };
8
+ /**
9
+ * Secondary port for sequence position tracking.
10
+ *
11
+ * Tracks which response in a sequence should be returned next for each
12
+ * (testId + scenarioId + mockIndex) combination.
13
+ *
14
+ * This port enables:
15
+ * - Default implementation: In-memory tracking (Map-based)
16
+ * - Redis implementation: Distributed testing across processes
17
+ * - File-based implementation: Persistent state across restarts
18
+ * - Test doubles: Mock sequence tracking for adapter tests
19
+ */
20
+ export interface SequenceTracker {
21
+ /**
22
+ * Get the current sequence position for a specific mock.
23
+ *
24
+ * @param testId - Test ID for isolation
25
+ * @param scenarioId - Scenario ID
26
+ * @param mockIndex - Index of the mock in the scenario's mocks array
27
+ * @returns Current position (0-indexed) and exhaustion status
28
+ */
29
+ getPosition(testId: string, scenarioId: string, mockIndex: number): SequencePosition;
30
+ /**
31
+ * Advance the sequence position for a specific mock.
32
+ *
33
+ * @param testId - Test ID for isolation
34
+ * @param scenarioId - Scenario ID
35
+ * @param mockIndex - Index of the mock in the scenario's mocks array
36
+ * @param totalResponses - Total number of responses in the sequence
37
+ * @param repeatMode - Repeat behavior ('last' | 'cycle' | 'none')
38
+ */
39
+ advance(testId: string, scenarioId: string, mockIndex: number, totalResponses: number, repeatMode: 'last' | 'cycle' | 'none'): void;
40
+ /**
41
+ * Reset all sequence positions for a specific test ID.
42
+ *
43
+ * Called when switching scenarios to ensure sequences start fresh.
44
+ *
45
+ * @param testId - Test ID to reset
46
+ */
47
+ reset(testId: string): void;
48
+ }
49
+ //# sourceMappingURL=sequence-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sequence-tracker.d.ts","sourceRoot":"","sources":["../../../src/ports/driven/sequence-tracker.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,WAAW,CACT,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,gBAAgB,CAAC;IAEpB;;;;;;;;OAQG;IACH,OAAO,CACL,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GACpC,IAAI,CAAC;IAER;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,56 @@
1
+ /**
2
+ * StateManager port for managing runtime state in stateful mocks (Phase 3).
3
+ *
4
+ * Implementations store state per test ID, enabling:
5
+ * - Capturing values from requests
6
+ * - Injecting state into responses via templates
7
+ * - State isolation between concurrent tests
8
+ *
9
+ * State values MUST be JSON-serializable to support distributed implementations:
10
+ * - ✅ Primitives: string, number, boolean, null
11
+ * - ✅ Objects and arrays (plain data)
12
+ * - ❌ Functions, classes, symbols, undefined, circular references
13
+ *
14
+ * This enables multiple implementations:
15
+ * - InMemoryStateManager (default): Fast, single-process
16
+ * - RedisStateManager (future): Distributed testing
17
+ * - FileSystemStateManager (future): Persistent state
18
+ */
19
+ export interface StateManager {
20
+ /**
21
+ * Get a state value for a specific test ID.
22
+ *
23
+ * @param testId - Test identifier for state isolation
24
+ * @param key - State key (can be nested path like 'user.profile.name')
25
+ * @returns Value from state, or undefined if not found
26
+ */
27
+ get(testId: string, key: string): unknown;
28
+ /**
29
+ * Set a state value for a specific test ID.
30
+ *
31
+ * @param testId - Test identifier for state isolation
32
+ * @param key - State key (supports nested paths)
33
+ * @param value - Value to store (must be JSON-serializable)
34
+ */
35
+ set(testId: string, key: string, value: unknown): void;
36
+ /**
37
+ * Get all state for a specific test ID.
38
+ *
39
+ * @param testId - Test identifier
40
+ * @returns Complete state object for this test ID
41
+ */
42
+ getAll(testId: string): Record<string, unknown>;
43
+ /**
44
+ * Reset all state for a specific test ID.
45
+ *
46
+ * Called automatically by ScenarioManager when switching scenarios to prevent
47
+ * state pollution between scenarios. Tests may also call this manually to reset
48
+ * state mid-test.
49
+ *
50
+ * Note: New test IDs start with empty state automatically (no reset needed).
51
+ *
52
+ * @param testId - Test identifier
53
+ */
54
+ reset(testId: string): void;
55
+ }
56
+ //# sourceMappingURL=state-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-manager.d.ts","sourceRoot":"","sources":["../../../src/ports/driven/state-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAE1C;;;;;;OAMG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAEvD;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEhD;;;;;;;;;;OAUG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,99 @@
1
+ import type { ScenaristScenario, ActiveScenario, ScenaristResult } from '../../types/index.js';
2
+ /**
3
+ * Primary port for scenario management.
4
+ *
5
+ * ScenarioManager is a coordinator/facade that orchestrates interactions between
6
+ * ScenarioRegistry (catalog of available scenarios) and ScenarioStore (active
7
+ * scenarios per test ID). It enforces business rules and provides a unified API.
8
+ *
9
+ * **Architectural Role:**
10
+ * - Coordinates between registry and store
11
+ * - Enforces business rules (e.g., can't activate non-existent scenarios)
12
+ * - Provides test isolation via test IDs
13
+ * - Main entry point for scenario operations
14
+ *
15
+ * **Implementation Pattern:**
16
+ * Implementations accept ScenarioRegistry and ScenarioStore as constructor
17
+ * parameters (dependency injection), never creating them internally.
18
+ *
19
+ * Note: Config is NOT needed here - it's used by adapters (middleware, RequestContext)
20
+ * to handle HTTP concerns. ScenarioManager is pure domain logic.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * // Factory function accepts both ports as dependencies
25
+ * const manager = createScenarioManager({
26
+ * registry: new InMemoryScenarioRegistry(),
27
+ * store: new InMemoryScenarioStore(),
28
+ * });
29
+ * ```
30
+ *
31
+ * **Thread Safety:**
32
+ * Implementations must be thread-safe for concurrent test execution.
33
+ */
34
+ export interface ScenarioManager {
35
+ /**
36
+ * Register a scenario definition in the catalog.
37
+ *
38
+ * Delegates to: ScenarioRegistry.register()
39
+ *
40
+ * @param definition The scenario definition to register
41
+ * @throws Error if scenario ID is already registered
42
+ */
43
+ registerScenario(definition: ScenaristScenario): void;
44
+ /**
45
+ * Switch to a different scenario for a specific test ID.
46
+ *
47
+ * Business rule: Validates scenario exists in registry before activating.
48
+ * Delegates to: ScenarioRegistry.get() then ScenarioStore.set()
49
+ *
50
+ * This enables test isolation - different tests can run different scenarios.
51
+ *
52
+ * @param testId Unique identifier for the test
53
+ * @param scenarioId ID of the scenario to activate
54
+ * @returns Success or error if scenario not found in registry
55
+ */
56
+ switchScenario(testId: string, scenarioId: string): ScenaristResult<void, Error>;
57
+ /**
58
+ * Get the currently active scenario reference for a test ID.
59
+ *
60
+ * Delegates to: ScenarioStore.get()
61
+ *
62
+ * Note: This returns only the reference (scenarioId).
63
+ * To get the full ScenarioDefinition, use getScenarioById().
64
+ *
65
+ * @param testId Unique identifier for the test
66
+ * @returns Active scenario reference or undefined if no scenario active
67
+ */
68
+ getActiveScenario(testId: string): ActiveScenario | undefined;
69
+ /**
70
+ * List all registered scenario definitions from the catalog.
71
+ *
72
+ * Delegates to: ScenarioRegistry.list()
73
+ *
74
+ * Useful for debugging and dev tools.
75
+ *
76
+ * @returns Array of all registered scenario definitions
77
+ */
78
+ listScenarios(): ReadonlyArray<ScenaristScenario>;
79
+ /**
80
+ * Clear the active scenario for a specific test ID.
81
+ *
82
+ * Delegates to: ScenarioStore.delete()
83
+ *
84
+ * Useful for cleanup after tests.
85
+ *
86
+ * @param testId Unique identifier for the test
87
+ */
88
+ clearScenario(testId: string): void;
89
+ /**
90
+ * Get a registered scenario definition by ID without activating it.
91
+ *
92
+ * Delegates to: ScenarioRegistry.get()
93
+ *
94
+ * @param id Scenario definition ID
95
+ * @returns Scenario definition or undefined if not found
96
+ */
97
+ getScenarioById(id: string): ScenaristScenario | undefined;
98
+ }
99
+ //# sourceMappingURL=scenario-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-manager.d.ts","sourceRoot":"","sources":["../../../src/ports/driving/scenario-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE/F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,gBAAgB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAEtD;;;;;;;;;;;OAWG;IACH,cAAc,CACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAEhC;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IAE9D;;;;;;;;OAQG;IACH,aAAa,IAAI,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAElD;;;;;;;;OAQG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAAC;CAC5D"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export type { ScenarioManager } from './driving/scenario-manager.js';
2
+ export type { ScenarioRegistry } from './driven/scenario-registry.js';
3
+ export type { ScenarioStore } from './driven/scenario-store.js';
4
+ export type { RequestContext } from './driven/request-context.js';
5
+ export type { ResponseSelector } from './driven/response-selector.js';
6
+ export type { SequenceTracker, SequencePosition } from './driven/sequence-tracker.js';
7
+ export type { StateManager } from './driven/state-manager.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACtF,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Runtime validation schemas for domain data.
3
+ *
4
+ * **Architectural Principle:**
5
+ * Schemas in this directory define domain validation rules.
6
+ * Framework adapters use these schemas at trust boundaries (external → internal).
7
+ *
8
+ * **Pattern:**
9
+ * 1. Define schema using Zod
10
+ * 2. Export both schema and derived type
11
+ * 3. Adapters import and apply at trust boundaries
12
+ * 4. NEVER duplicate schemas in adapters
13
+ */
14
+ export { ScenarioRequestSchema, type ScenarioRequest } from './scenario-requests.js';
15
+ export { ScenariosObjectSchema } from './scenarios-object.js';
16
+ export { HttpMethodSchema, ScenaristResponseSchema, MatchValueSchema, ScenaristMatchSchema, RepeatModeSchema, ScenaristSequenceSchema, ScenaristCaptureConfigSchema, ScenaristUrlPatternSchema, ScenaristMockSchema, ScenaristScenarioSchema, type HttpMethod, type ScenaristResponse, type MatchValue, type ScenaristMatch, type RepeatMode, type ScenaristSequence, type ScenaristCaptureConfig, type ScenaristUrlPattern, type ScenaristMock, type ScenaristScenario, } from './scenario-definition.js';
17
+ export { SerializedRegexSchema, type SerializedRegex } from './match-criteria.js';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,EACzB,mBAAmB,EACnB,uBAAuB,EAEvB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,iBAAiB,GACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Runtime validation schemas for domain data.
3
+ *
4
+ * **Architectural Principle:**
5
+ * Schemas in this directory define domain validation rules.
6
+ * Framework adapters use these schemas at trust boundaries (external → internal).
7
+ *
8
+ * **Pattern:**
9
+ * 1. Define schema using Zod
10
+ * 2. Export both schema and derived type
11
+ * 3. Adapters import and apply at trust boundaries
12
+ * 4. NEVER duplicate schemas in adapters
13
+ */
14
+ export { ScenarioRequestSchema } from './scenario-requests.js';
15
+ export { ScenariosObjectSchema } from './scenarios-object.js';
16
+ export { HttpMethodSchema, ScenaristResponseSchema, MatchValueSchema, ScenaristMatchSchema, RepeatModeSchema, ScenaristSequenceSchema, ScenaristCaptureConfigSchema, ScenaristUrlPatternSchema, ScenaristMockSchema, ScenaristScenarioSchema, } from './scenario-definition.js';
17
+ export { SerializedRegexSchema } from './match-criteria.js';
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Schema for serialized regex patterns.
4
+ *
5
+ * **Security Notes:**
6
+ * - Uses redos-detector to prevent ReDoS attacks
7
+ * - Validates regex flags to prevent injection
8
+ * - Source must be non-empty string
9
+ *
10
+ * **Serialization:**
11
+ * Regex patterns are serialized as plain objects to maintain JSON compatibility.
12
+ * This allows scenarios to be stored in files, databases, or transmitted over network.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const regex: SerializedRegex = {
17
+ * source: '/api/products',
18
+ * flags: 'i'
19
+ * };
20
+ * ```
21
+ */
22
+ export declare const SerializedRegexSchema: z.ZodObject<{
23
+ source: z.ZodString;
24
+ flags: z.ZodOptional<z.ZodString>;
25
+ }, z.core.$strip>;
26
+ export type SerializedRegex = z.infer<typeof SerializedRegexSchema>;
27
+ //# sourceMappingURL=match-criteria.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match-criteria.d.ts","sourceRoot":"","sources":["../../src/schemas/match-criteria.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2CxB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,qBAAqB;;;iBAWhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -0,0 +1,71 @@
1
+ import { z } from 'zod';
2
+ import { isSafePattern } from 'redos-detector';
3
+ /**
4
+ * Zod schemas for match criteria with regex support.
5
+ *
6
+ * **Security:**
7
+ * - ReDoS protection via redos-detector
8
+ * - Only safe regex flag characters allowed
9
+ * - Timeout protection handled separately in domain layer
10
+ *
11
+ * **Pattern:**
12
+ * Serialize regex as { source: string, flags?: string } for JSON compatibility.
13
+ */
14
+ /**
15
+ * Valid regex flags (safe subset of JavaScript regex flags).
16
+ *
17
+ * Supported flags:
18
+ * - g: global match
19
+ * - i: case insensitive
20
+ * - m: multiline
21
+ * - s: dotAll (. matches newlines)
22
+ * - u: unicode
23
+ * - v: unicode sets
24
+ * - y: sticky
25
+ */
26
+ const VALID_REGEX_FLAGS = /^[gimsuvy]*$/;
27
+ /**
28
+ * Validates that a regex pattern is safe from ReDoS attacks.
29
+ *
30
+ * Uses redos-detector to analyze the pattern for exponential backtracking.
31
+ * Patterns that could cause catastrophic backtracking are rejected.
32
+ *
33
+ * @param pattern - The regex pattern to validate
34
+ * @returns true if the pattern is safe, false otherwise
35
+ */
36
+ const isPatternSafeFromReDoS = (pattern) => {
37
+ const result = isSafePattern(pattern);
38
+ return result.safe;
39
+ };
40
+ /**
41
+ * Schema for serialized regex patterns.
42
+ *
43
+ * **Security Notes:**
44
+ * - Uses redos-detector to prevent ReDoS attacks
45
+ * - Validates regex flags to prevent injection
46
+ * - Source must be non-empty string
47
+ *
48
+ * **Serialization:**
49
+ * Regex patterns are serialized as plain objects to maintain JSON compatibility.
50
+ * This allows scenarios to be stored in files, databases, or transmitted over network.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const regex: SerializedRegex = {
55
+ * source: '/api/products',
56
+ * flags: 'i'
57
+ * };
58
+ * ```
59
+ */
60
+ export const SerializedRegexSchema = z.object({
61
+ source: z
62
+ .string()
63
+ .min(1, 'Regex source must not be empty')
64
+ .refine(isPatternSafeFromReDoS, {
65
+ message: 'Regex pattern is unsafe (ReDoS vulnerability detected)',
66
+ }),
67
+ flags: z
68
+ .string()
69
+ .regex(VALID_REGEX_FLAGS, 'Invalid regex flags (only g, i, m, s, u, v, y allowed)')
70
+ .optional(),
71
+ });