@http-forge/core 0.3.3 → 0.4.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.
Files changed (28) hide show
  1. package/README.md +2 -1
  2. package/dist/di/service-container.d.ts +1 -1
  3. package/dist/di/service-identifiers.d.ts +1 -0
  4. package/dist/index.d.ts +9 -1
  5. package/dist/index.js +573 -277
  6. package/dist/index.mjs +573 -277
  7. package/dist/infrastructure/config/config.interface.d.ts +32 -0
  8. package/dist/infrastructure/environment/environment-config-service.d.ts +29 -17
  9. package/dist/infrastructure/environment/environment-file-loader.d.ts +5 -0
  10. package/dist/infrastructure/execution/request-executor.d.ts +2 -4
  11. package/dist/infrastructure/execution/request-preparer.d.ts +3 -1
  12. package/dist/infrastructure/script/interfaces.d.ts +1 -2
  13. package/dist/infrastructure/script/script-executor.d.ts +10 -1
  14. package/dist/infrastructure/script/script-factories.d.ts +25 -0
  15. package/dist/infrastructure/secrets/aws-secret-resolver.d.ts +18 -0
  16. package/dist/infrastructure/secrets/azure-keyvault-resolver.d.ts +20 -0
  17. package/dist/infrastructure/secrets/doppler-resolver.d.ts +22 -0
  18. package/dist/infrastructure/secrets/gcp-secret-resolver.d.ts +21 -0
  19. package/dist/infrastructure/secrets/hashicorp-vault-resolver.d.ts +25 -0
  20. package/dist/infrastructure/secrets/onepassword-resolver.d.ts +26 -0
  21. package/dist/infrastructure/secrets/secret-resolver-registry.d.ts +43 -0
  22. package/dist/infrastructure/test-suite/html-report-generator.d.ts +24 -1
  23. package/dist/infrastructure/test-suite/result-storage-service.d.ts +1 -1
  24. package/dist/infrastructure/test-suite/result-storage.d.ts +45 -3
  25. package/dist/types/environment-config.d.ts +16 -7
  26. package/dist/types/secret-resolver.d.ts +106 -0
  27. package/dist/types/types.d.ts +6 -0
  28. package/package.json +13 -1
@@ -110,6 +110,36 @@ export interface ProxyConfig {
110
110
  /** List of hosts to bypass proxy */
111
111
  bypass?: string[];
112
112
  }
113
+ /**
114
+ * Cloud secret provider configuration (used in SecretsConfig.providers)
115
+ */
116
+ export interface SecretProviderEntry {
117
+ /** Provider type */
118
+ provider: 'aws' | 'azure' | 'gcp' | 'vault' | '1password' | 'doppler';
119
+ /** AWS region (aws only) */
120
+ region?: string;
121
+ /** Azure Key Vault URL (azure only) */
122
+ vaultUrl?: string;
123
+ /** GCP project ID (gcp only) */
124
+ projectId?: string;
125
+ /** Vault server address (vault only) */
126
+ address?: string;
127
+ /** Vault mount path (vault only, default "secret") */
128
+ mountPath?: string;
129
+ /** Vault namespace (vault only, Enterprise/HCP) */
130
+ namespace?: string;
131
+ /** 1Password vault name (1password only) */
132
+ vault?: string;
133
+ /** Doppler service token (doppler only; falls back to DOPPLER_TOKEN env var) */
134
+ serviceToken?: string;
135
+ }
136
+ /**
137
+ * Top-level secrets block in http-forge.config.json
138
+ * Configures named cloud secret providers for {{secret:alias/path}} tokens.
139
+ */
140
+ export interface SecretsConfig {
141
+ providers: Record<string, SecretProviderEntry>;
142
+ }
113
143
  /**
114
144
  * Main HTTP Forge configuration (http-forge.config.json)
115
145
  */
@@ -132,6 +162,8 @@ export interface HttpForgeConfig {
132
162
  mcp?: McpConfig;
133
163
  /** Proxy configuration (optional) */
134
164
  proxy?: ProxyConfig | null;
165
+ /** Cloud secret provider configuration (optional) */
166
+ secrets?: SecretsConfig;
135
167
  }
136
168
  /**
137
169
  * Configuration service interface
@@ -5,13 +5,14 @@
5
5
  * VS Code's workspaceState/globalState.
6
6
  */
7
7
  import type { IEnvironmentConfigService, ImportedEnvironment, LocalConfig, ResolvedEnvironment, SharedConfig } from '../../types/environment-config';
8
- import { IFileWatcherFactory, IKeyValueStore } from '../../types/platform';
8
+ import { IFileWatcherFactory, IKeyValueStore, ISecretStore } from '../../types/platform';
9
9
  import { IConfigService } from '../config';
10
10
  export declare class EnvironmentConfigService implements IEnvironmentConfigService {
11
11
  private workspaceFolder;
12
12
  private workspaceStore;
13
13
  private configService;
14
14
  private fileWatcherFactory?;
15
+ private secretStore?;
15
16
  private environmentsPath;
16
17
  private sharedConfigPath;
17
18
  private localConfigPath;
@@ -27,12 +28,14 @@ export declare class EnvironmentConfigService implements IEnvironmentConfigServi
27
28
  */
28
29
  private localGlobalValues;
29
30
  private localEnvironmentValues;
31
+ /** In-memory cache of secret values fetched from SecretStorage — keyed by envName */
32
+ private secretValuesCache;
30
33
  /**
31
34
  * Callback invoked when environment files change on disk.
32
35
  * Set by the extension host to refresh tree views and panels.
33
36
  */
34
37
  onEnvironmentsChanged?: () => void;
35
- constructor(workspaceFolder: string, workspaceStore: IKeyValueStore, configService: IConfigService, fileWatcherFactory?: IFileWatcherFactory | undefined);
38
+ constructor(workspaceFolder: string, workspaceStore: IKeyValueStore, configService: IConfigService, fileWatcherFactory?: IFileWatcherFactory | undefined, secretStore?: ISecretStore | undefined);
36
39
  private setupFileWatcher;
37
40
  dispose(): void;
38
41
  getWorkspaceFolder(): string;
@@ -53,9 +56,9 @@ export declare class EnvironmentConfigService implements IEnvironmentConfigServi
53
56
  * Persist current environment overrides to workspace state (fire-and-forget).
54
57
  */
55
58
  private persistEnvironmentOverrides;
56
- setEnvironmentVariable(key: string, value: unknown): void;
57
- deleteEnvironmentVariable(key: string): void;
58
- clearEnvironmentVariables(): void;
59
+ setEnvironmentVariable(key: string, value: unknown, envName?: string): void;
60
+ deleteEnvironmentVariable(key: string, envName?: string): void;
61
+ clearEnvironmentVariables(envName?: string): void;
59
62
  /**
60
63
  * Reset all runtime environment overrides for the current environment.
61
64
  * Equivalent to Postman's "Reset All" — reverts Current Values to Initial Values.
@@ -70,19 +73,28 @@ export declare class EnvironmentConfigService implements IEnvironmentConfigServi
70
73
  getGlobalVariableLocals(): Record<string, string>;
71
74
  deleteGlobalVariable(key: string): void;
72
75
  clearGlobalVariables(): void;
73
- /** @deprecated Use setEnvironmentVariable instead */
74
- setSessionVariable(key: string, value: unknown): Promise<void>;
75
- /** @deprecated Use getEnvironmentVariableLocal instead */
76
- getSessionVariable(key: string): string | undefined;
77
- /** @deprecated Use getEnvironmentVariableLocals instead */
78
- getSessionVariables(): Record<string, string>;
79
- /** @deprecated Use deleteEnvironmentVariable instead */
80
- deleteSessionVariable(key: string): Promise<void>;
81
- /** @deprecated Use clearEnvironmentVariables instead */
82
- clearSessionVariables(): Promise<void>;
83
- /** @deprecated Use getEnvironmentVariableLocal instead */
84
- hasSessionVariable(key: string): boolean;
85
76
  getResolvedEnvironment(envName?: string): ResolvedEnvironment | null;
77
+ /**
78
+ * Retrieve a secret variable value from SecretStorage.
79
+ * Returns undefined when no SecretStorage is available (e.g. CLI context).
80
+ */
81
+ getSecretVariable(envName: string, key: string): Promise<string | undefined>;
82
+ /**
83
+ * Store a secret variable value in SecretStorage.
84
+ * No-op when no SecretStorage is available (e.g. CLI context).
85
+ */
86
+ setSecretVariable(envName: string, key: string, value: string): Promise<void>;
87
+ /**
88
+ * Delete a secret variable from SecretStorage.
89
+ * No-op when no SecretStorage is available (e.g. CLI context).
90
+ */
91
+ deleteSecretVariable(envName: string, key: string): Promise<void>;
92
+ /**
93
+ * Pre-load all secret values for an environment into the in-memory cache.
94
+ * Call this when switching environments or on extension activation so that
95
+ * the synchronous getResolvedEnvironment() always has secret values available.
96
+ */
97
+ loadSecretVariables(envName?: string): Promise<void>;
86
98
  resolveVariables(input: string, envName?: string): string;
87
99
  exportEnvironmentsToFolder(outDir: string, mergeGlobals?: boolean): void;
88
100
  resolveVariablesWithExtra(input: string, extraVariables: Record<string, string>, envName?: string): string;
@@ -28,6 +28,11 @@ export interface EnvironmentEntry {
28
28
  description?: string;
29
29
  requiresConfirmation?: boolean;
30
30
  variables: Record<string, string>;
31
+ /**
32
+ * Names of variables whose values are stored in SecretStorage, not in the JSON file.
33
+ * These names are persisted in the JSON; the values are never written to disk.
34
+ */
35
+ secretVariables?: string[];
31
36
  }
32
37
  /**
33
38
  * Determine whether a filename is a system/meta file (not an environment file).
@@ -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
  }
@@ -15,6 +15,7 @@ import { ExecutionRequest, PreparedRequest } from '../../types/types';
15
15
  import { IOAuth2TokenManager } from '../auth/interfaces';
16
16
  import { IHttpRequestService } from '../http/interfaces';
17
17
  import { IRequestPreprocessor } from '../http/request-preprocessor';
18
+ import { SecretResolverRegistry } from '../secrets/secret-resolver-registry';
18
19
  import { IRequestPreparer } from './request-preparer-interfaces';
19
20
  /**
20
21
  * RequestPreparer implementation
@@ -28,7 +29,8 @@ export declare class RequestPreparer implements IRequestPreparer {
28
29
  private readonly preprocessor;
29
30
  private readonly tokenManager?;
30
31
  private readonly appInfo?;
31
- constructor(envConfigService: IEnvironmentConfigService, httpService: IHttpRequestService, preprocessor: IRequestPreprocessor, tokenManager?: IOAuth2TokenManager | undefined, appInfo?: IApplicationInfo | undefined);
32
+ private readonly secretRegistry?;
33
+ constructor(envConfigService: IEnvironmentConfigService, httpService: IHttpRequestService, preprocessor: IRequestPreprocessor, tokenManager?: IOAuth2TokenManager | undefined, appInfo?: IApplicationInfo | undefined, secretRegistry?: SecretResolverRegistry | undefined);
32
34
  prepareRequest(input: ExecutionRequest, environment: string, resolvedEnv: ResolvedEnvironment, extraVariables?: Record<string, string>): Promise<PreparedRequest>;
33
35
  private applyOAuth2;
34
36
  private applyApiKey;
@@ -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;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * AWS Secrets Manager resolver
3
+ *
4
+ * Uses the AWS SDK v3 credential chain — no credentials are stored in HTTP Forge config.
5
+ * Order: env vars → ~/.aws/credentials → IAM instance role → ECS task role
6
+ *
7
+ * Token syntax: {{secret:aws/<secretId>}}
8
+ * e.g. {{secret:aws/myapp/prod/db-password}}
9
+ * {{secret:aws/myapp/prod/api-key#field}} (JSON secret field)
10
+ */
11
+ import type { AwsSecretsConfig, ISecretResolver } from '../../types/secret-resolver';
12
+ export declare class AwsSecretResolver implements ISecretResolver {
13
+ readonly providerName = "aws";
14
+ private readonly region;
15
+ private readonly moduleRequire;
16
+ constructor(config: AwsSecretsConfig, moduleRequire?: (name: string) => any);
17
+ resolve(path: string): Promise<string | undefined>;
18
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Azure Key Vault resolver
3
+ *
4
+ * Uses DefaultAzureCredential — no credentials stored in HTTP Forge config.
5
+ * Order: env vars (AZURE_*) → managed identity → Azure CLI login → VS Code login
6
+ *
7
+ * Token syntax: {{secret:azure/<secretName>}}
8
+ * e.g. {{secret:azure/my-api-key}}
9
+ * {{secret:azure/my-api-key/1.0}} (specific version)
10
+ *
11
+ * Config requires vaultUrl, e.g. "https://myvault.vault.azure.net"
12
+ */
13
+ import type { AzureKeyVaultConfig, ISecretResolver } from '../../types/secret-resolver';
14
+ export declare class AzureKeyVaultResolver implements ISecretResolver {
15
+ readonly providerName = "azure";
16
+ private readonly vaultUrl;
17
+ private readonly moduleRequire;
18
+ constructor(config: AzureKeyVaultConfig, moduleRequire?: (name: string) => any);
19
+ resolve(path: string): Promise<string | undefined>;
20
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Doppler secret resolver
3
+ *
4
+ * Uses the Doppler REST API — no SDK required, just a service token.
5
+ * Credentials: DOPPLER_TOKEN env var (or serviceToken in config for per-project override)
6
+ *
7
+ * Token syntax: {{secret:doppler/<secretName>}}
8
+ * e.g. {{secret:doppler/API_KEY}}
9
+ * {{secret:doppler/DATABASE_URL}}
10
+ *
11
+ * The Doppler project/config are baked into the service token itself —
12
+ * no project or config fields needed in http-forge.config.json.
13
+ *
14
+ * Prerequisites: none (uses Node.js built-in https)
15
+ */
16
+ import type { DopplerConfig, ISecretResolver } from '../../types/secret-resolver';
17
+ export declare class DopplerResolver implements ISecretResolver {
18
+ readonly providerName = "doppler";
19
+ private readonly token;
20
+ constructor(config: DopplerConfig);
21
+ resolve(path: string): Promise<string | undefined>;
22
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Google Cloud Secret Manager resolver
3
+ *
4
+ * Uses Application Default Credentials — no credentials stored in HTTP Forge config.
5
+ * Order: GOOGLE_APPLICATION_CREDENTIALS env var → gcloud CLI login → Workload Identity (GKE)
6
+ * → Metadata server (Cloud Run, Compute Engine)
7
+ *
8
+ * Token syntax: {{secret:gcp/<secretName>}}
9
+ * {{secret:gcp/<secretName>/versions/<version>}} (specific version, default: latest)
10
+ *
11
+ * Config: { "provider": "gcp", "projectId": "my-project" }
12
+ * projectId falls back to GOOGLE_CLOUD_PROJECT / GCLOUD_PROJECT env vars.
13
+ */
14
+ import type { GcpSecretsConfig, ISecretResolver } from '../../types/secret-resolver';
15
+ export declare class GcpSecretResolver implements ISecretResolver {
16
+ readonly providerName = "gcp";
17
+ private readonly projectId;
18
+ private readonly moduleRequire;
19
+ constructor(config: GcpSecretsConfig, moduleRequire?: (name: string) => any);
20
+ resolve(path: string): Promise<string | undefined>;
21
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * HashiCorp Vault resolver
3
+ *
4
+ * Credentials are NEVER stored in HTTP Forge config.
5
+ * Authentication uses:
6
+ * VAULT_TOKEN env var (token auth)
7
+ * VAULT_ADDR env var (server address, overrides config)
8
+ * VAULT_NAMESPACE env var (Enterprise/HCP namespace, overridden by config.namespace)
9
+ *
10
+ * Token syntax: {{secret:vault/<mountPath>/<secretPath>#<field>}}
11
+ * e.g. {{secret:vault/secret/myapp/prod#db_password}}
12
+ * {{secret:vault/kv/myapp/config#api_key}}
13
+ *
14
+ * The path format after the provider prefix: <mount>/<path>#<field>
15
+ * If no field is specified and the secret has a single key "value", that is returned.
16
+ */
17
+ import type { HashiCorpVaultConfig, ISecretResolver } from '../../types/secret-resolver';
18
+ export declare class HashiCorpVaultResolver implements ISecretResolver {
19
+ readonly providerName = "vault";
20
+ private readonly address;
21
+ private readonly mountPath;
22
+ private readonly namespace;
23
+ constructor(config: HashiCorpVaultConfig);
24
+ resolve(path: string): Promise<string | undefined>;
25
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 1Password Connect / Service Account resolver
3
+ *
4
+ * Credentials are NEVER stored in HTTP Forge config.
5
+ * Authentication uses:
6
+ * OP_SERVICE_ACCOUNT_TOKEN env var (1Password Service Account — recommended for CI)
7
+ * OP_CONNECT_TOKEN + OP_CONNECT_HOST env vars (1Password Connect Server)
8
+ *
9
+ * Token syntax: {{secret:1password/<vault>/<item>/<field>}}
10
+ * e.g. {{secret:1password/MyVault/MyApp/api_key}}
11
+ * {{secret:1password/Shared/prod-db/password}}
12
+ *
13
+ * If `vault` is specified in the provider config, the token path may omit it:
14
+ * {{secret:1password/<item>/<field>}}
15
+ *
16
+ * Uses the 1Password CLI (`op`) via child_process if SDK is unavailable.
17
+ */
18
+ import type { ISecretResolver, OnePasswordConfig } from '../../types/secret-resolver';
19
+ export declare class OnePasswordResolver implements ISecretResolver {
20
+ readonly providerName = "1password";
21
+ private readonly defaultVault;
22
+ constructor(config: OnePasswordConfig);
23
+ resolve(path: string): Promise<string | undefined>;
24
+ private tryResolveSdk;
25
+ private resolveViaCli;
26
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Secret Resolver Registry — Phase 3
3
+ *
4
+ * Builds and caches ISecretResolver instances from config, and provides
5
+ * async pre-resolution of {{secret:provider/path}} tokens in template strings.
6
+ *
7
+ * Design:
8
+ * - Registry is created once at startup from IConfigService
9
+ * - resolveSecretTokens() is called BEFORE variable interpolation per-request
10
+ * - Resolved values are injected as extraVariables so the sync VariableResolver
11
+ * picks them up transparently
12
+ * - Results are cached within a single request lifetime to avoid redundant API calls
13
+ */
14
+ import type { IConfigService } from '../config/config.interface';
15
+ export declare class SecretResolverRegistry {
16
+ private readonly resolvers;
17
+ /**
18
+ * Require function rooted at the user's project (via config `scripts.modulePaths`),
19
+ * so optional cloud SDKs resolve from the same place users install custom script
20
+ * modules — not from the extension's own bundle.
21
+ */
22
+ private readonly moduleRequire;
23
+ constructor(configService?: IConfigService);
24
+ /**
25
+ * Scan a string (or recursively, any object) for {{secret:alias/path}} tokens
26
+ * and resolve them all in parallel.
27
+ *
28
+ * Returns a flat map of "secret:alias/path" → plaintext value
29
+ * suitable for injection as extraVariables into VariableResolver.
30
+ */
31
+ resolveSecretTokens(input: any, cache?: Map<string, string>): Promise<Record<string, string>>;
32
+ /** Whether any providers are configured */
33
+ get hasProviders(): boolean;
34
+ private collectTokens;
35
+ private createResolver;
36
+ /**
37
+ * Build a `require` function rooted at the user's project, so optional cloud SDKs
38
+ * resolve from the same `node_modules` where users install custom script modules
39
+ * (via config `scripts.modulePaths`). Falls back to the default `require` so the
40
+ * CLI (which lists SDKs in optionalDependencies) still works without modulePaths.
41
+ */
42
+ private buildModuleRequire;
43
+ }
@@ -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
  }
@@ -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
  */
@@ -11,6 +11,11 @@ export interface EnvironmentConfig {
11
11
  description?: string;
12
12
  requiresConfirmation?: boolean;
13
13
  variables?: Record<string, string>;
14
+ /**
15
+ * Names of variables whose values are stored in SecretStorage rather than the JSON file.
16
+ * The JSON file stores the variable name only; the value is fetched at resolution time.
17
+ */
18
+ secretVariables?: string[];
14
19
  }
15
20
  /**
16
21
  * Shared configuration file structure
@@ -95,18 +100,14 @@ export interface IVariableResolver {
95
100
  * Variable management operations (for scripts)
96
101
  */
97
102
  export interface IVariableManager {
98
- setEnvironmentVariable(key: string, value: unknown): void;
99
- deleteEnvironmentVariable(key: string): void;
100
- clearEnvironmentVariables(): void;
103
+ setEnvironmentVariable(key: string, value: unknown, envName?: string): void;
104
+ deleteEnvironmentVariable(key: string, envName?: string): void;
105
+ clearEnvironmentVariables(envName?: string): void;
101
106
  getEnvironmentVariableLocals(): Record<string, string>;
102
107
  setGlobalVariable(key: string, value: unknown): void;
103
108
  getGlobalVariable(key: string): string | undefined;
104
109
  deleteGlobalVariable(key: string): void;
105
110
  clearGlobalVariables(): void;
106
- setSessionVariable(key: string, value: unknown): void;
107
- deleteSessionVariable(key: string): Promise<void>;
108
- clearSessionVariables(): Promise<void>;
109
- getSessionVariables(): Record<string, string>;
110
111
  getGlobalVariables(): Record<string, string>;
111
112
  }
112
113
  /**
@@ -115,6 +116,14 @@ export interface IVariableManager {
115
116
  export interface IEnvironmentConfigService extends IEnvironmentConfigReader, IEnvironmentConfigWriter, IEnvironmentSelector, IVariableResolver, IVariableManager {
116
117
  loadConfigs(): void;
117
118
  exportEnvironmentsToFolder(outDir: string, mergeGlobals?: boolean): void;
119
+ /** Read a single secret variable from SecretStorage. */
120
+ getSecretVariable(envName: string, key: string): Promise<string | undefined>;
121
+ /** Store a secret variable value in SecretStorage. */
122
+ setSecretVariable(envName: string, key: string, value: string): Promise<void>;
123
+ /** Delete a secret variable from SecretStorage. */
124
+ deleteSecretVariable(envName: string, key: string): Promise<void>;
125
+ /** Load all secrets for an environment (or current) into cache. */
126
+ loadSecretVariables(envName?: string): Promise<void>;
118
127
  }
119
128
  /**
120
129
  * Interface for storing and retrieving environment variables