@http-forge/core 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -56,9 +56,9 @@ export declare class EnvironmentConfigService implements IEnvironmentConfigServi
56
56
  * Persist current environment overrides to workspace state (fire-and-forget).
57
57
  */
58
58
  private persistEnvironmentOverrides;
59
- setEnvironmentVariable(key: string, value: unknown): void;
60
- deleteEnvironmentVariable(key: string): void;
61
- clearEnvironmentVariables(): void;
59
+ setEnvironmentVariable(key: string, value: unknown, envName?: string): void;
60
+ deleteEnvironmentVariable(key: string, envName?: string): void;
61
+ clearEnvironmentVariables(envName?: string): void;
62
62
  /**
63
63
  * Reset all runtime environment overrides for the current environment.
64
64
  * Equivalent to Postman's "Reset All" — reverts Current Values to Initial Values.
@@ -73,18 +73,6 @@ export declare class EnvironmentConfigService implements IEnvironmentConfigServi
73
73
  getGlobalVariableLocals(): Record<string, string>;
74
74
  deleteGlobalVariable(key: string): void;
75
75
  clearGlobalVariables(): void;
76
- /** @deprecated Use setEnvironmentVariable instead */
77
- setSessionVariable(key: string, value: unknown): Promise<void>;
78
- /** @deprecated Use getEnvironmentVariableLocal instead */
79
- getSessionVariable(key: string): string | undefined;
80
- /** @deprecated Use getEnvironmentVariableLocals instead */
81
- getSessionVariables(): Record<string, string>;
82
- /** @deprecated Use deleteEnvironmentVariable instead */
83
- deleteSessionVariable(key: string): Promise<void>;
84
- /** @deprecated Use clearEnvironmentVariables instead */
85
- clearSessionVariables(): Promise<void>;
86
- /** @deprecated Use getEnvironmentVariableLocal instead */
87
- hasSessionVariable(key: string): boolean;
88
76
  getResolvedEnvironment(envName?: string): ResolvedEnvironment | null;
89
77
  /**
90
78
  * Retrieve a secret variable value from SecretStorage.
@@ -4,11 +4,11 @@
4
4
  * Single Responsibility: Orchestrate the complete request execution flow
5
5
  * Facade Pattern: Provides simplified interface to complex subsystem
6
6
  */
7
+ import { IHttpClient } from '../../types/platform';
8
+ import { HttpRequest, HttpResponse, RequestOverrides, ScriptResult, UnifiedCollection, UnifiedRequest } from '../../types/types';
7
9
  import { IForgeEnv } from '../environment/forge-env';
8
10
  import { IRequestPreprocessor } from '../http/request-preprocessor';
9
11
  import { IScriptExecutor } from '../script/interfaces';
10
- import { IHttpClient } from '../../types/platform';
11
- import { HttpRequest, HttpResponse, RequestOverrides, ScriptResult, UnifiedCollection, UnifiedRequest } from '../../types/types';
12
12
  /**
13
13
  * Options for request execution
14
14
  */
@@ -25,8 +25,6 @@ export interface ExecuteOptions {
25
25
  additionalVariables?: Record<string, string>;
26
26
  /** Timeout override */
27
27
  timeout?: number;
28
- /** Callback when scripts modify session variables */
29
- onSessionChange?: (action: 'set' | 'unset' | 'clear', key?: string, value?: string) => void;
30
28
  /** Callback when scripts modify environment variables */
31
29
  onEnvironmentChange?: (action: 'set' | 'unset' | 'clear', key?: string, value?: string) => void;
32
30
  }
@@ -7,8 +7,8 @@
7
7
  * Dependency Inversion: Define abstractions for request execution components
8
8
  * Interface Segregation: Each interface has a focused purpose
9
9
  */
10
- import { Cookie } from '../cookie/interfaces';
11
10
  import { PreparedRequest, RequestAuth, RequestBody, RequestScripts, RequestSettings, ScriptInfo, TestAssertion } from '../../types/types';
11
+ import { Cookie } from '../cookie/interfaces';
12
12
  export type { Cookie, ScriptInfo };
13
13
  /**
14
14
  * Cookie Jar Interface
@@ -69,7 +69,6 @@ export interface CommonScriptContext {
69
69
  iteration?: number;
70
70
  iterationCount?: number;
71
71
  iterationData?: Record<string, any>;
72
- onSessionChange?: (action: 'set' | 'unset' | 'clear', key?: string, value?: string) => void;
73
72
  onEnvironmentChange?: (action: 'set' | 'unset' | 'clear', key?: string, value?: string) => void;
74
73
  }
75
74
  /**
@@ -9,6 +9,7 @@
9
9
  * It configures the VM sandbox and delegates session management to RequestScriptSession.
10
10
  */
11
11
  import { IHttpRequestService } from '../http/interfaces';
12
+ import { SecretResolverRegistry } from '../secrets/secret-resolver-registry';
12
13
  import { IRequestScriptSession, IScriptExecutor, PreRequestScriptContext } from './interfaces';
13
14
  /**
14
15
  * Script Executor Implementation
@@ -20,8 +21,9 @@ import { IRequestScriptSession, IScriptExecutor, PreRequestScriptContext } from
20
21
  */
21
22
  export declare class ScriptExecutor implements IScriptExecutor {
22
23
  private readonly httpService?;
24
+ private readonly secretRegistry?;
23
25
  private readonly moduleLoader;
24
- constructor(httpService?: IHttpRequestService | undefined, modulePaths?: string[]);
26
+ constructor(httpService?: IHttpRequestService | undefined, modulePaths?: string[], secretRegistry?: SecretResolverRegistry | undefined);
25
27
  /**
26
28
  * Create a request execution session
27
29
  * Factory method implementing IScriptExecutor
@@ -60,6 +62,13 @@ export declare class ScriptExecutor implements IScriptExecutor {
60
62
  * Create environment variable scope with change callbacks
61
63
  */
62
64
  private createEnvironmentScope;
65
+ /**
66
+ * Create the Postman-compatible pm.vault namespace.
67
+ * Reads are backed by HTTP Forge's secret provider system using the same
68
+ * {{secret:provider/path}} resolution. Writes are not supported (read-only),
69
+ * and resolved values are never persisted to console/report output here.
70
+ */
71
+ private createVault;
63
72
  /**
64
73
  * Create sendRequest function using httpService
65
74
  */
@@ -5,6 +5,15 @@
5
5
  * Open/Closed: New factory methods can be added without modifying existing ones
6
6
  */
7
7
  import { ResponseContext } from './interfaces';
8
+ /**
9
+ * Minimal, dependency-free JSON Schema validator.
10
+ *
11
+ * Supports the common subset used in API tests (draft-04 style):
12
+ * `type`, `properties`, `required`, `items`, `enum`, `additionalProperties`
13
+ * (boolean), `minimum`/`maximum`, `minLength`/`maxLength`, and `pattern`.
14
+ * Returns a list of human-readable error strings (empty when valid).
15
+ */
16
+ export declare function validateJsonSchema(data: any, schema: any, path?: string): string[];
8
17
  /**
9
18
  * Response object interface for script context
10
19
  */
@@ -36,6 +45,7 @@ export interface ResponseAssertions {
36
45
  header(headerName: string, expectedValue?: string): void;
37
46
  body(expectedBody?: string): void;
38
47
  jsonBody(expectedJson?: any): void;
48
+ jsonSchema(schema: any): void;
39
49
  };
40
50
  be: {
41
51
  readonly ok: any;
@@ -62,12 +72,27 @@ export interface ExpectChain {
62
72
  be: ExpectChain;
63
73
  have: ExpectChain;
64
74
  deep: ExpectChain;
75
+ and: ExpectChain;
76
+ that: ExpectChain;
77
+ which: ExpectChain;
78
+ is: ExpectChain;
79
+ been: ExpectChain;
80
+ has: ExpectChain;
81
+ with: ExpectChain;
82
+ at: ExpectChain;
83
+ of: ExpectChain;
84
+ same: ExpectChain;
85
+ but: ExpectChain;
86
+ does: ExpectChain;
87
+ still: ExpectChain;
88
+ also: ExpectChain;
65
89
  equal(expected: any): ExpectChain;
66
90
  eql(expected: any): ExpectChain;
67
91
  property(name: string, value?: any): ExpectChain;
68
92
  ok: ExpectChain;
69
93
  exist: ExpectChain;
70
94
  include(value: any): ExpectChain;
95
+ contain(value: any): ExpectChain;
71
96
  oneOf(values: any[]): ExpectChain;
72
97
  match(pattern: RegExp): ExpectChain;
73
98
  above(num: number): ExpectChain;
@@ -5,6 +5,13 @@
5
5
  * generates a self-contained single-file HTML report (no external dependencies).
6
6
  *
7
7
  * Output: {basePath}/{suiteId}/{runId}/report.html
8
+ *
9
+ * Each request entry expands to show:
10
+ * - Full request URL, method, headers, body
11
+ * - Response status, headers, body (pretty-printed)
12
+ * - All test assertions (pass/fail + messages)
13
+ * - Console output (if any)
14
+ * - Error message (if any)
8
15
  */
9
16
  export declare class HtmlReportGenerator {
10
17
  private readonly basePath;
@@ -15,6 +22,22 @@ export declare class HtmlReportGenerator {
15
22
  */
16
23
  generate(suiteId: string, runId: string): Promise<string>;
17
24
  private loadAllSummaries;
18
- private loadFailedDetails;
25
+ /** Load every result file for every request (pass + fail). */
26
+ private loadAllDetails;
27
+ /**
28
+ * Group summaries by iteration, then by (collection + folder path),
29
+ * preserving execution order within each tier.
30
+ */
31
+ private groupByIterCollectionFolder;
32
+ /**
33
+ * Build a combined group header label like:
34
+ * "01 - MyCollection: Auth/Login"
35
+ * Collection or folder parts are omitted when empty; falls back to "(root)".
36
+ */
37
+ private groupLabel;
38
+ /** Render the detail accordions grouped by iteration → (collection + folder). */
39
+ private renderGroupedDetails;
40
+ /** Render the timeline table rows grouped by iteration → (collection + folder). */
41
+ private renderGroupedTimeline;
19
42
  private buildHtml;
20
43
  }
@@ -147,6 +147,7 @@ export interface ITestSuiteService {
147
147
  deleteSuite(id: string): Promise<boolean>;
148
148
  duplicateSuite(sourceId: string, newName: string): Promise<TestSuite>;
149
149
  createTempSuiteFromCollection(collectionId: string): Promise<TestSuite | undefined>;
150
+ createTempSuiteFromFolder(collectionId: string, folderPath: string, recursive?: boolean): Promise<TestSuite | undefined>;
150
151
  saveTempSuite(suite: TestSuite, name: string): Promise<TestSuite>;
151
152
  }
152
153
  /**
@@ -45,7 +45,7 @@ export declare class ResultStorageService implements IResultStorageService {
45
45
  * Finalize run
46
46
  * @returns path to the generated HTML report, or null if generation failed
47
47
  */
48
- finalizeRun(status?: 'completed' | 'aborted' | 'error'): Promise<string | null>;
48
+ finalizeRun(status?: 'completed' | 'aborted' | 'error', generateHtmlReport?: boolean): Promise<string | null>;
49
49
  getCurrentStats(): {
50
50
  stats: RunStats;
51
51
  requestStats: Record<string, RequestStats>;
@@ -39,6 +39,10 @@ export interface ResultSummary {
39
39
  r: string;
40
40
  /** Error message if failed (e) - null if passed */
41
41
  e: string | null;
42
+ /** Folder path (fp) - slash-separated; omitted/empty for root-level requests */
43
+ fp?: string;
44
+ /** Collection name (cn) - omitted/empty when unknown */
45
+ cn?: string;
42
46
  }
43
47
  /**
44
48
  * Build result filename from summary components
@@ -169,6 +173,10 @@ export interface FullResultDetails {
169
173
  method: string;
170
174
  /** Full URL */
171
175
  url: string;
176
+ /** Folder path within the collection (slash-separated; empty for root) */
177
+ folderPath?: string;
178
+ /** Name of the collection this request belongs to */
179
+ collectionName?: string;
172
180
  /** HTTP status code */
173
181
  status: number;
174
182
  /** HTTP status text */
@@ -181,13 +189,27 @@ export interface FullResultDetails {
181
189
  timestamp: number;
182
190
  /** Request details */
183
191
  request: {
192
+ method: string;
193
+ url: string;
184
194
  headers: Record<string, string>;
185
- body: any;
195
+ query: Record<string, string>;
196
+ params: Record<string, string>;
197
+ body: {
198
+ type: string;
199
+ format?: string;
200
+ content: any;
201
+ };
186
202
  };
187
203
  /** Response details */
188
204
  response: {
189
205
  headers: Record<string, string | string[]>;
190
206
  body: any;
207
+ time?: number;
208
+ size?: number;
209
+ cookies?: Array<{
210
+ name?: string;
211
+ value?: string;
212
+ }>;
191
213
  };
192
214
  /** Test assertions */
193
215
  assertions: Array<{
@@ -197,6 +219,23 @@ export interface FullResultDetails {
197
219
  }>;
198
220
  /** Error message */
199
221
  error: string | null;
222
+ /** Console output produced while running the request */
223
+ consoleOutput?: string[];
224
+ /** Variables modified by pre/post scripts */
225
+ modifiedVariables?: Record<string, string>;
226
+ /** Environment variables modified by scripts */
227
+ modifiedEnvironmentVariables?: Record<string, string>;
228
+ /** Collection variables modified by scripts */
229
+ modifiedCollectionVariables?: Record<string, string>;
230
+ /** Session variables modified by scripts */
231
+ modifiedSessionVariables?: Record<string, string>;
232
+ /** pm.execution.setNextRequest() value */
233
+ nextRequest?: string | null;
234
+ /** pm.visualizer.set() payload */
235
+ visualizerData?: {
236
+ template: string;
237
+ data?: any;
238
+ };
200
239
  }
201
240
  /**
202
241
  * Index page containing summaries
@@ -248,9 +287,12 @@ export interface IResultStorageService {
248
287
  saveResult(iteration: number, result: ExecutionResult): Promise<ResultSummary>;
249
288
  /**
250
289
  * Finalize run
251
- * @returns path to the generated HTML report, or null if generation failed
290
+ * @param status final run status
291
+ * @param generateHtmlReport when false, the run is persisted (manifest + results)
292
+ * but the HTML report is not generated; returns null in that case
293
+ * @returns path to the generated HTML report, or null if not generated / generation failed
252
294
  */
253
- finalizeRun(status: 'completed' | 'aborted' | 'error'): Promise<string | null>;
295
+ finalizeRun(status: 'completed' | 'aborted' | 'error', generateHtmlReport?: boolean): Promise<string | null>;
254
296
  /**
255
297
  * Get current run stats
256
298
  */
@@ -79,6 +79,16 @@ export declare class TestSuiteService implements ITestSuiteService {
79
79
  * Create a temporary suite from a collection
80
80
  */
81
81
  createTempSuiteFromCollection(collectionId: string): Promise<TestSuite | undefined>;
82
+ /**
83
+ * Create a temporary suite from a single folder within a collection.
84
+ *
85
+ * @param collectionId - the owning collection
86
+ * @param folderPath - slash-separated folder names (e.g. "Auth/Login")
87
+ * @param recursive - include requests in nested subfolders (default: true)
88
+ */
89
+ createTempSuiteFromFolder(collectionId: string, folderPath: string, recursive?: boolean): Promise<TestSuite | undefined>;
90
+ /** Convert a folder path into an id-safe slug. */
91
+ private slugifyFolderPath;
82
92
  /**
83
93
  * Save a temporary suite as a permanent one
84
94
  */
@@ -20,6 +20,15 @@ export declare function runRequest(options: RunRequestOptions): Promise<unknown>
20
20
  * Returns typed result; never calls process.exit.
21
21
  */
22
22
  export declare function runCollection(options: RunCollectionOptions): Promise<unknown>;
23
+ /**
24
+ * Execute the requests under a specific folder of a collection without MCP
25
+ * server overhead. Thin wrapper over {@link runCollection} that scopes the run
26
+ * to `options.folderPath` (recursively by default). Returns the same result
27
+ * shape as a collection run.
28
+ */
29
+ export declare function runFolder(options: RunCollectionOptions & {
30
+ folderPath: string;
31
+ }): Promise<unknown>;
23
32
  /**
24
33
  * Execute a test suite without MCP server overhead.
25
34
  * Returns typed result; never calls process.exit.
@@ -84,6 +84,16 @@ export interface RunCollectionOptions {
84
84
  delay?: number;
85
85
  /** Extra response fields to include: perRequest, failedOnly, consoleOutput */
86
86
  include?: string[];
87
+ /**
88
+ * Restrict execution to requests under this folder path (slash-separated
89
+ * folder names, e.g. "Auth/Login"). When omitted, the whole collection runs.
90
+ */
91
+ folderPath?: string;
92
+ /**
93
+ * When a `folderPath` is provided, include requests in nested subfolders
94
+ * (default: true). When false, only requests directly in that folder run.
95
+ */
96
+ recursive?: boolean;
87
97
  }
88
98
  /**
89
99
  * Options for directly executing a test suite without MCP.
@@ -118,6 +128,14 @@ export declare function runRequest(options: RunRequestOptions): Promise<unknown>
118
128
  * Returns typed result object; never calls process.exit.
119
129
  */
120
130
  export declare function runCollection(options: RunCollectionOptions): Promise<unknown>;
131
+ /**
132
+ * Execute the requests under a specific folder of a collection without MCP
133
+ * server. Thin wrapper over {@link runCollection} scoped to `folderPath`
134
+ * (recursively by default). Returns the same result shape as a collection run.
135
+ */
136
+ export declare function runFolder(options: RunCollectionOptions & {
137
+ folderPath: string;
138
+ }): Promise<unknown>;
121
139
  /**
122
140
  * Execute a test suite directly without MCP server.
123
141
  * Returns typed result object; never calls process.exit.
@@ -100,18 +100,14 @@ export interface IVariableResolver {
100
100
  * Variable management operations (for scripts)
101
101
  */
102
102
  export interface IVariableManager {
103
- setEnvironmentVariable(key: string, value: unknown): void;
104
- deleteEnvironmentVariable(key: string): void;
105
- clearEnvironmentVariables(): void;
103
+ setEnvironmentVariable(key: string, value: unknown, envName?: string): void;
104
+ deleteEnvironmentVariable(key: string, envName?: string): void;
105
+ clearEnvironmentVariables(envName?: string): void;
106
106
  getEnvironmentVariableLocals(): Record<string, string>;
107
107
  setGlobalVariable(key: string, value: unknown): void;
108
108
  getGlobalVariable(key: string): string | undefined;
109
109
  deleteGlobalVariable(key: string): void;
110
110
  clearGlobalVariables(): void;
111
- setSessionVariable(key: string, value: unknown): void;
112
- deleteSessionVariable(key: string): Promise<void>;
113
- clearSessionVariables(): Promise<void>;
114
- getSessionVariables(): Record<string, string>;
115
111
  getGlobalVariables(): Record<string, string>;
116
112
  }
117
113
  /**
@@ -292,6 +292,8 @@ export interface TestAssertion {
292
292
  name: string;
293
293
  passed: boolean;
294
294
  message?: string;
295
+ /** True when the test was explicitly skipped via pm.test.skip(...) */
296
+ skipped?: boolean;
295
297
  }
296
298
  /**
297
299
  * Request overrides that can be applied at runtime
@@ -619,6 +621,10 @@ export interface ExecutionResult {
619
621
  modifiedCollectionVariables?: Record<string, string>;
620
622
  modifiedSessionVariables?: Record<string, string>;
621
623
  error?: string;
624
+ /** Folder path of the request within its collection (slash-separated; empty for root) */
625
+ folderPath?: string;
626
+ /** Name of the collection this request belongs to (for multi-collection suite reports) */
627
+ collectionName?: string;
622
628
  /** Postman-compatible: pm.execution.setNextRequest() value. null = stop runner. */
623
629
  nextRequest?: string | null;
624
630
  /** Postman-compatible: pm.visualizer.set(template, data) output */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@http-forge/core",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Headless HTTP testing engine with Postman collection support, dynamic variables, and script-based automation.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",