@http-forge/core 0.1.0 → 0.2.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 (135) hide show
  1. package/README.md +217 -43
  2. package/dist/auth/interfaces.d.ts +63 -0
  3. package/dist/auth/oauth2-token-manager.d.ts +103 -0
  4. package/dist/collection/collection-loader-factory.d.ts +20 -0
  5. package/dist/{services → collection}/collection-loader.d.ts +3 -3
  6. package/dist/collection/collection-service-interfaces.d.ts +119 -0
  7. package/dist/collection/collection-service.d.ts +75 -0
  8. package/dist/collection/collection-store.d.ts +109 -0
  9. package/dist/collection/folder-collection-loader.d.ts +45 -0
  10. package/dist/collection/folder-collection-store.d.ts +175 -0
  11. package/dist/collection/folder-io.d.ts +113 -0
  12. package/dist/collection/interfaces.d.ts +32 -0
  13. package/dist/collection/json-collection-loader.d.ts +95 -0
  14. package/dist/{services → collection}/parser-registry.d.ts +1 -2
  15. package/dist/config/config-service.d.ts +79 -0
  16. package/dist/config/config.interface.d.ts +140 -0
  17. package/dist/config/default-config.d.ts +29 -0
  18. package/dist/config/index.d.ts +6 -0
  19. package/dist/container.d.ts +26 -19
  20. package/dist/{implementations → cookie}/cookie-jar.d.ts +2 -3
  21. package/dist/cookie/cookie-service.d.ts +98 -0
  22. package/dist/{implementations → cookie}/cookie-utils.d.ts +1 -2
  23. package/dist/cookie/in-memory-cookie-jar.d.ts +44 -0
  24. package/dist/{interfaces/cookie.d.ts → cookie/interfaces.d.ts} +22 -3
  25. package/dist/cookie/persistent-cookie-jar.d.ts +35 -0
  26. package/dist/di/core-bootstrap.d.ts +25 -0
  27. package/dist/di/index.d.ts +11 -0
  28. package/dist/di/platform-adapters.d.ts +53 -0
  29. package/dist/di/service-container.d.ts +97 -0
  30. package/dist/di/service-identifiers.d.ts +34 -0
  31. package/dist/environment/environment-config-service.d.ts +98 -0
  32. package/dist/environment/environment-file-loader.d.ts +42 -0
  33. package/dist/{services → environment}/environment-resolver.d.ts +6 -5
  34. package/dist/{services → environment}/forge-env.d.ts +1 -2
  35. package/dist/environment/interfaces.d.ts +139 -0
  36. package/dist/environment/variable-interpolator.d.ts +100 -0
  37. package/dist/execution/collection-request-executor-interfaces.d.ts +36 -0
  38. package/dist/execution/collection-request-executor.d.ts +78 -0
  39. package/dist/{services → execution}/request-executor.d.ts +23 -11
  40. package/dist/execution/request-preparer-interfaces.d.ts +36 -0
  41. package/dist/execution/request-preparer.d.ts +35 -0
  42. package/dist/graphql/graphql-completion-provider.d.ts +39 -0
  43. package/dist/graphql/graphql-schema-service.d.ts +89 -0
  44. package/dist/{interfaces/history.d.ts → history/history-interfaces.d.ts} +29 -6
  45. package/dist/history/request-history-service-interfaces.d.ts +43 -0
  46. package/dist/history/request-history-service.d.ts +133 -0
  47. package/dist/{implementations → history}/request-history.d.ts +2 -3
  48. package/dist/{implementations → http}/fetch-http-client.d.ts +4 -5
  49. package/dist/http/http-request-service.d.ts +36 -0
  50. package/dist/{implementations → http}/interceptor-chain.d.ts +1 -2
  51. package/dist/http/interfaces.d.ts +25 -0
  52. package/dist/http/merge-request-settings.d.ts +12 -0
  53. package/dist/{implementations → http}/native-http-client.d.ts +6 -15
  54. package/dist/{implementations → http}/request-preprocessor.d.ts +1 -2
  55. package/dist/{services → http}/url-builder.d.ts +7 -10
  56. package/dist/import-export/import-postman-environment.d.ts +21 -0
  57. package/dist/import-export/rest-client-export.d.ts +35 -0
  58. package/dist/index.d.ts +94 -6
  59. package/dist/index.js +262 -35
  60. package/dist/index.mjs +262 -35
  61. package/dist/openapi/example-generator.d.ts +26 -0
  62. package/dist/openapi/history-analyzer.d.ts +29 -0
  63. package/dist/openapi/index.d.ts +16 -0
  64. package/dist/openapi/interfaces.d.ts +42 -0
  65. package/dist/openapi/openapi-exporter.d.ts +73 -0
  66. package/dist/openapi/openapi-importer.d.ts +72 -0
  67. package/dist/openapi/ref-resolver.d.ts +28 -0
  68. package/dist/openapi/schema-inference-service.d.ts +40 -0
  69. package/dist/openapi/schema-inferrer.d.ts +26 -0
  70. package/dist/openapi/script-analyzer.d.ts +41 -0
  71. package/dist/parsers/http-forge-parser.d.ts +2 -3
  72. package/dist/parsers/index.d.ts +0 -1
  73. package/dist/{implementations → platform}/data-file-parser.d.ts +0 -1
  74. package/dist/{implementations → platform}/node-file-system.d.ts +1 -2
  75. package/dist/script/interfaces.d.ts +161 -0
  76. package/dist/script/module-loader.d.ts +115 -0
  77. package/dist/script/request-script-session.d.ts +73 -0
  78. package/dist/script/script-executor.d.ts +60 -0
  79. package/dist/script/script-factories.d.ts +94 -0
  80. package/dist/script/script-utils.d.ts +42 -0
  81. package/dist/test-suite/index.d.ts +10 -0
  82. package/dist/test-suite/interfaces.d.ts +164 -0
  83. package/dist/test-suite/result-storage-service.d.ts +70 -0
  84. package/dist/test-suite/result-storage.d.ts +296 -0
  85. package/dist/test-suite/statistics-service.d.ts +51 -0
  86. package/dist/test-suite/test-suite-service.d.ts +97 -0
  87. package/dist/test-suite/test-suite-store.d.ts +155 -0
  88. package/dist/types/console-service.d.ts +40 -0
  89. package/dist/types/platform.d.ts +206 -0
  90. package/dist/{interfaces → types}/types.d.ts +289 -12
  91. package/dist/utils/dynamic-variables.d.ts +38 -0
  92. package/dist/utils/expression-evaluator.d.ts +34 -0
  93. package/dist/utils/filter-engine.d.ts +47 -0
  94. package/dist/utils/helpers.d.ts +47 -0
  95. package/package.json +12 -4
  96. package/dist/container.d.ts.map +0 -1
  97. package/dist/implementations/cookie-jar.d.ts.map +0 -1
  98. package/dist/implementations/cookie-utils.d.ts.map +0 -1
  99. package/dist/implementations/data-file-parser.d.ts.map +0 -1
  100. package/dist/implementations/fetch-http-client.d.ts.map +0 -1
  101. package/dist/implementations/index.d.ts +0 -22
  102. package/dist/implementations/index.d.ts.map +0 -1
  103. package/dist/implementations/interceptor-chain.d.ts.map +0 -1
  104. package/dist/implementations/module-loader.d.ts +0 -74
  105. package/dist/implementations/module-loader.d.ts.map +0 -1
  106. package/dist/implementations/native-http-client.d.ts.map +0 -1
  107. package/dist/implementations/node-file-system.d.ts.map +0 -1
  108. package/dist/implementations/request-history.d.ts.map +0 -1
  109. package/dist/implementations/request-preprocessor.d.ts.map +0 -1
  110. package/dist/implementations/variable-interpolator.d.ts +0 -55
  111. package/dist/implementations/variable-interpolator.d.ts.map +0 -1
  112. package/dist/implementations/vm2-script-runner.d.ts +0 -76
  113. package/dist/implementations/vm2-script-runner.d.ts.map +0 -1
  114. package/dist/index.d.ts.map +0 -1
  115. package/dist/interfaces/cookie.d.ts.map +0 -1
  116. package/dist/interfaces/history.d.ts.map +0 -1
  117. package/dist/interfaces/index.d.ts +0 -170
  118. package/dist/interfaces/index.d.ts.map +0 -1
  119. package/dist/interfaces/types.d.ts.map +0 -1
  120. package/dist/parsers/http-forge-parser.d.ts.map +0 -1
  121. package/dist/parsers/index.d.ts.map +0 -1
  122. package/dist/services/collection-loader.d.ts.map +0 -1
  123. package/dist/services/environment-resolver.d.ts.map +0 -1
  124. package/dist/services/folder-collection-loader.d.ts +0 -91
  125. package/dist/services/folder-collection-loader.d.ts.map +0 -1
  126. package/dist/services/forge-env.d.ts.map +0 -1
  127. package/dist/services/index.d.ts +0 -20
  128. package/dist/services/index.d.ts.map +0 -1
  129. package/dist/services/parser-registry.d.ts.map +0 -1
  130. package/dist/services/request-executor.d.ts.map +0 -1
  131. package/dist/services/script-pipeline.d.ts +0 -43
  132. package/dist/services/script-pipeline.d.ts.map +0 -1
  133. package/dist/services/script-session.d.ts +0 -66
  134. package/dist/services/script-session.d.ts.map +0 -1
  135. package/dist/services/url-builder.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,26 +1,32 @@
1
1
  # @http-forge/core
2
2
 
3
- **Lightweight, VS Code-independent HTTP API testing engine** - The execution core of HTTP Forge.
3
+ **Standalone HTTP testing engine with Postman collection support and JavaScript-based automation.**
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@http-forge/core.svg)](https://www.npmjs.com/package/@http-forge/core)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
8
  ## 📦 What is @http-forge/core?
9
9
 
10
- `@http-forge/core` is a standalone, dependency-injection-based HTTP execution engine that powers HTTP Forge. It provides a clean API for:
11
-
12
- - 🚀 Executing HTTP requests with full HTTP Forge collection support
13
- - 🔄 Running pre-request and post-response scripts
14
- - 🌍 Managing environments and variables
15
- - 🍪 Automatic cookie handling
16
- - 📊 Test assertions and validations
17
- - 🔌 Extensible via interceptors and custom implementations
18
-
19
- **Perfect for:**
20
- - Building custom API testing tools
21
- - Integrating HTTP Forge into CI/CD pipelines
22
- - Creating CLI tools for API testing
23
- - Headless API testing automation
10
+ `@http-forge/core` is a headless, framework-agnostic HTTP execution engine with **full Postman collection compatibility**. Execute complex API workflows, test suites, and automated flows without the overhead of a UI.
11
+
12
+ **Core Features:**
13
+ - 🚀 **Postman Collections** - Load and execute `.postman_collection.json` and `.forge.json` files
14
+ - 📝 **JavaScript Scripting** - Pre-request and post-response scripts with full `pm.*` API (variables, assertions, execution flow, visualizer)
15
+ - 🔄 **Dynamic Variables** - Built-in generators: `{{$randomInt}}`, `{{$timestamp}}`, `{{$uuid}}`, `{{$guid}}`, etc.
16
+ - 🌍 **Environments** - Full variable scoping (globals, collection, environment, session, iterationData)
17
+ - 🍪 **Cookie Persistence** - Automatic cookie storage and reuse, `pm.cookies.jar()` and `.toObject()`
18
+ - 📊 **Test Assertions** - BDD-style testing with `pm.test()` (sync/async) and full Chai `expect()` chains
19
+ - 🔐 **CryptoJS** - Full crypto library: hash, HMAC, AES/DES/TripleDES, PBKDF2, encoding helpers
20
+ - 🎯 **Execution Flow** - `pm.setNextRequest()`, `pm.execution.skipRequest()` for suite runner flow control
21
+ - 📈 **Visualizer** - `pm.visualizer.set(template, data)` for custom Handlebars-based HTML output
22
+ - 🔌 **Extensible** - Custom interceptors, HTTP clients, and module loaders
23
+
24
+ **Ideal for:**
25
+ - CI/CD pipeline integration (GitHub Actions, GitLab CI, Jenkins)
26
+ - Headless API testing and contract validation
27
+ - Building custom API testing CLIs
28
+ - Load testing and performance monitoring
29
+ - Automated integration test suites
24
30
 
25
31
  ## 🎯 Installation
26
32
 
@@ -141,29 +147,79 @@ console.log(result.preRequestResult); // Pre-request script output
141
147
  console.log(result.postResponseResult); // Test results
142
148
  ```
143
149
 
150
+ ### Dynamic Variables
151
+
152
+ Automatic variable generation within request templates:
153
+
154
+ ```javascript
155
+ // URL with dynamic timestamp
156
+ https://api.example.com/events?timestamp={{$timestamp}}
157
+
158
+ // Headers with unique ID
159
+ X-Request-ID: {{$uuid}}
160
+
161
+ // Query parameters with random value
162
+ ?page=1&seed={{$randomInt:1:100}}
163
+ ```
164
+
165
+ **Supported dynamic variables:**
166
+ - `{{$randomInt}}` - Random integer (0-2147483647)
167
+ - `{{$randomInt:min:max}}` - Random integer in range
168
+ - `{{$timestamp}}` - Current Unix timestamp (seconds)
169
+ - `{{$uuid}}` - UUID v4
170
+ - `{{$guid}}` - GUID (alias for uuid)
171
+ - `{{$randomString}}` - 10-char alphanumeric string
172
+ - `{{$randomHexadecimal}}` - Random hex string
173
+ - `{{$isoTimestamp}}` - ISO 8601 timestamp
174
+
144
175
  ### Script Execution
145
176
 
146
- Run pre-request and post-response scripts:
177
+ Run pre-request and post-response scripts with full Postman API compatibility:
147
178
 
148
- **Pre-request script:**
179
+ **Pre-request script - Set variables & modify request:**
149
180
  ```javascript
150
- // Set variables before request
151
- forge.env.set('timestamp', Date.now());
152
- forge.env.set('requestId', forge.uuid());
181
+ // Set variables across scopes
182
+ pm.variables.set('requestId', pm.variables.randomUUID());
183
+ pm.environment.set('token', 'abc-123');
184
+ pm.collectionVariables.set('counter', '1');
185
+
186
+ // Modify request headers
187
+ pm.request.headers.add({
188
+ name: 'X-Request-ID',
189
+ value: pm.variables.get('requestId')
190
+ });
191
+ pm.request.headers.update({
192
+ name: 'Authorization',
193
+ value: 'Bearer ' + pm.environment.get('token')
194
+ });
153
195
 
154
- // Modify request
155
- forge.request.headers['X-Request-ID'] = forge.env.get('requestId');
196
+ // Modify URL and body
197
+ pm.request.url = 'https://api.example.com' + pm.request.url;
198
+ pm.request.body.raw = JSON.stringify({ timestamp: Date.now() });
199
+
200
+ // Set cookies for next request
201
+ pm.cookies.set('sessionId', 'sess_abc123');
156
202
  ```
157
203
 
158
- **Post-response script:**
204
+ **Post-response script - Test & extract data:**
159
205
  ```javascript
160
- // Run tests
161
- forge.expect(forge.response.status).toBe(200);
162
- forge.expect(forge.response.body.success).toBeTruthy();
206
+ // Run assertions
207
+ pm.test('Status is 200', () => {
208
+ pm.expect(pm.response.code).to.equal(200);
209
+ });
210
+ pm.test('Response time under 1s', () => {
211
+ pm.expect(pm.response.responseTime).to.be.below(1000);
212
+ });
163
213
 
164
- // Extract data from response
165
- const token = forge.response.body.token;
166
- forge.env.set('authToken', token);
214
+ // Extract data for next request
215
+ const data = pm.response.json();
216
+ pm.environment.set('userId', data.id);
217
+ pm.environment.set('authToken', data.token);
218
+
219
+ // Store cookies from response
220
+ if (pm.response.headers.has('Set-Cookie')) {
221
+ pm.cookies.set('authCookie', data.authCookie);
222
+ }
167
223
  ```
168
224
 
169
225
  ### Environment Management
@@ -240,21 +296,49 @@ const forge = new ForgeContainer({
240
296
  });
241
297
  ```
242
298
 
243
- ### Cookie Management
299
+ ### Cookie Management & Persistence
244
300
 
245
- Automatic cookie handling across requests:
301
+ Automatic cookie storage and reuse across multi-request flows:
246
302
 
247
303
  ```typescript
248
304
  const forge = new ForgeContainer({
249
- enableCookies: true
305
+ enableCookies: true // Cookies persist across requests in session
250
306
  });
251
307
 
252
- // Cookies are automatically stored and sent
308
+ // Login - response sets Session-ID cookie
253
309
  const loginResult = await forge.execute(loginRequest, collection);
254
- // Session cookie from login is automatically included in next request
310
+
311
+ // Subsequent requests automatically include Session-ID
312
+ // No need to manually extract and re-add cookies
255
313
  const dataResult = await forge.execute(dataRequest, collection);
314
+ const updateResult = await forge.execute(updateRequest, collection);
315
+ ```
316
+
317
+ **Access cookies in scripts:**
318
+ ```javascript
319
+ // Pre-request script - read stored cookies
320
+ if (pm.cookies.has('sessionId')) {
321
+ const sid = pm.cookies.get('sessionId');
322
+ pm.request.headers.add({
323
+ name: 'Cookie',
324
+ value: 'sessionId=' + sid
325
+ });
326
+ }
327
+
328
+ // Post-response script - store new cookies
329
+ pm.response.cookies.forEach(cookie => {
330
+ pm.cookies.set(cookie.name, cookie.value);
331
+ });
332
+
333
+ // List all active cookies
334
+ const allCookies = pm.cookies.list(); // [{name, value}, ...]
335
+
336
+ // Clear cookies
337
+ pm.cookies.clear(); // When switching users/sessions
256
338
  ```
257
339
 
340
+ Cookies are automatically extracted from `Set-Cookie` response headers and reused in subsequent `Cookie` request headers.
341
+
258
342
  ### Request History
259
343
 
260
344
  Track all executed requests:
@@ -450,6 +534,72 @@ class ApiTestRunner {
450
534
  }
451
535
  ```
452
536
 
537
+ ### Multi-Request Workflows
538
+
539
+ Execute dependent request chains with automatic cookie and variable management:
540
+
541
+ ```typescript
542
+ import { ForgeContainer } from '@http-forge/core';
543
+
544
+ async function apiAuthWorkflow() {
545
+ const forge = new ForgeContainer({
546
+ enableCookies: true, // Cookies persist across requests
547
+ enableHistory: true
548
+ });
549
+
550
+ // Request 1: Login (sets session cookie)
551
+ const loginReq = {
552
+ name: 'Login',
553
+ method: 'POST',
554
+ url: 'https://api.example.com/auth/login',
555
+ body: { type: 'raw', content: JSON.stringify({
556
+ username: '{{email}}',
557
+ password: '{{password}}'
558
+ })},
559
+ scripts: {
560
+ postResponse: `
561
+ const { token, userId } = pm.response.json();
562
+ pm.environment.set('authToken', token);
563
+ pm.environment.set('userId', userId);
564
+ `
565
+ }
566
+ };
567
+
568
+ const loginResult = await forge.execute(loginReq, collection);
569
+ console.log('✓ Logged in, token:', forge.getResolvedEnvironment()['authToken']);
570
+
571
+ // Request 2: Fetch user profile (uses session cookie automatically)
572
+ const profileReq = {
573
+ name: 'Get Profile',
574
+ method: 'GET',
575
+ url: 'https://api.example.com/users/{{userId}}',
576
+ headers: {
577
+ 'Authorization': 'Bearer {{authToken}}' // Uses token from login
578
+ }
579
+ };
580
+
581
+ const profileResult = await forge.execute(profileReq, collection);
582
+ console.log('✓ Profile:', profileResult.response.body);
583
+
584
+ // Request 3: Update profile (session cookie still active)
585
+ const updateReq = {
586
+ name: 'Update Profile',
587
+ method: 'PATCH',
588
+ url: 'https://api.example.com/users/{{userId}}',
589
+ headers: {
590
+ 'Authorization': 'Bearer {{authToken}}'
591
+ },
592
+ body: { type: 'raw', content: JSON.stringify({ status: 'active' })}
593
+ };
594
+
595
+ const updateResult = await forge.execute(updateReq, collection);
596
+ console.log('✓ Updated profile');
597
+
598
+ // Session automatically logged out - cookies cleared
599
+ forge.getRequestHistory().clear();
600
+ }
601
+ ```
602
+
453
603
  ## 📦 Storage Formats
454
604
 
455
605
  ### File Format (Single JSON)
@@ -487,14 +637,38 @@ MIT © Henry Huang
487
637
 
488
638
  ## 📝 Changelog
489
639
 
640
+ ### 0.2.0 (Postman API Parity)
641
+
642
+ - ✅ **Async `pm.test()` support** - Tests with async callbacks are properly awaited
643
+ - ✅ **Expect chain assertions** - `.a(type)`, `.an(type)`, `.deep.equal()`, `.lengthOf()`, `.exist`, `.members()`, `.keys()`, `.string()`
644
+ - ✅ **`pm.iterationData`** scope - Data-driven testing with iteration variables
645
+ - ✅ **Response status getters** - `response.to.be.ok`, `.error`, `.clientError`, `.serverError` work as getters and functions
646
+ - ✅ **Response headers HeaderList** - `.get()`, `.has()`, `.toObject()`, `.each()` on `pm.response.headers`
647
+ - ✅ **`pm.cookies.toObject()`** - Flat `{name: value}` cookie map
648
+ - ✅ **`replaceIn()` on all scopes** - Available on `pm.variables`, `pm.environment`, `pm.collectionVariables`, `pm.globals`
649
+ - ✅ **Sandbox globals** - `xml2Json()`, `jsonStringify()`, `jsonParse()` available in scripts
650
+ - ✅ **Request headers API** - `.toObject()`, `.each()` on `pm.request.headers`
651
+ - ✅ **`pm.execution.setNextRequest()`** - Runner flow control (jump to named request or stop with `null`)
652
+ - ✅ **`pm.execution.skipRequest()`** - Skip HTTP call from pre-request scripts
653
+ - ✅ **`pm.setNextRequest()`** - Top-level alias for flow control
654
+ - ✅ **`pm.visualizer.set(template, data)`** - Custom HTML visualization with Handlebars templates
655
+ - ✅ **`pm.request.url` as Url object** - Postman SDK-compatible Url with `getHost()`, `getPath()`, `getQueryString()`, `protocol`, `host`, `port`, `path`, `query`, `hash`
656
+ - ✅ **Full CryptoJS** - AES/DES/TripleDES encrypt/decrypt, PBKDF2, all hash algorithms (SHA1/256/384/512/SHA3/MD5/RIPEMD160), HMAC, encoding helpers (Hex/Base64/Utf8/Latin1/Utf16)
657
+
490
658
  ### 0.1.0 (Initial Release)
491
659
 
492
- - ✅ Core request execution engine
493
- - ✅ Environment and variable management
494
- - ✅ Pre-request and post-response scripts
495
- - ✅ Cookie jar support
496
- - ✅ Request/response interceptors
497
- - ✅ Request history tracking
498
- - ✅ File and folder collection formats
499
- - ✅ Full TypeScript support
500
- - ✅ Comprehensive test coverage
660
+ - ✅ **Core request execution** with Postman collection support
661
+ - ✅ **Dynamic variables** - 7 generators for on-the-fly value generation
662
+ - ✅ **Postman-compatible scripting** - `pm.*` API with full feature parity
663
+ - ✅ **Variable scoping** - globals, collection, environment, session, flow-level
664
+ - ✅ **Cookie persistence** - automatic storage and reuse across request chains
665
+ - ✅ **Pre-request & post-response scripts** with shared VM context
666
+ - ✅ **Test assertions** with BDD-style `pm.test()` and expect chains
667
+ - ✅ **Environment management** with variable substitution
668
+ - ✅ **Cookie jar** with domain-aware matching
669
+ - ✅ **Request/response interceptors** for customization
670
+ - ✅ **Request history** tracking
671
+ - ✅ **File and folder collection formats** (Postman-compatible)
672
+ - ✅ **Full TypeScript support** with comprehensive types
673
+ - ✅ **Dependency injection** for extensibility
674
+ - ✅ **Comprehensive test coverage**
@@ -0,0 +1,63 @@
1
+ /**
2
+ * OAuth2 Token Manager Interface
3
+ *
4
+ * Platform-independent interface for OAuth2 token management.
5
+ * Handles all grant types: client_credentials, password, authorization_code, implicit.
6
+ *
7
+ * VS Code impl: uses vscode.env.openExternal, vscode.SecretStorage
8
+ * CLI/Standalone impl: uses system browser + local HTTP callback server
9
+ * Browser impl: uses window.open() + postMessage
10
+ */
11
+ import { OAuth2Config } from '../types/types';
12
+ export interface TokenInfo {
13
+ accessToken: string;
14
+ /** e.g. "Bearer" */
15
+ tokenType: string;
16
+ /** Unix timestamp (ms) */
17
+ expiresAt?: number;
18
+ refreshToken?: string;
19
+ scope?: string;
20
+ /** Original token response */
21
+ raw: Record<string, unknown>;
22
+ }
23
+ export interface TokenCacheKey {
24
+ tokenUrl: string;
25
+ clientId: string;
26
+ scope?: string;
27
+ grantType: string;
28
+ }
29
+ export interface IOAuth2TokenManager {
30
+ /**
31
+ * Get a valid access token for the given OAuth2 configuration.
32
+ * May return a cached token, refresh an expired token, or initiate a new flow.
33
+ */
34
+ getToken(config: OAuth2Config, environment: string): Promise<TokenInfo>;
35
+ /**
36
+ * Refresh an expired token using the refresh token.
37
+ */
38
+ refreshToken(config: OAuth2Config, currentRefreshToken: string, environment: string): Promise<TokenInfo>;
39
+ /**
40
+ * Initiate the authorization code flow (opens browser, waits for callback).
41
+ */
42
+ authorizationCodeFlow(config: OAuth2Config, environment: string): Promise<TokenInfo>;
43
+ /**
44
+ * Initiate the implicit flow (opens browser, waits for callback).
45
+ */
46
+ implicitFlow(config: OAuth2Config, environment: string): Promise<TokenInfo>;
47
+ /**
48
+ * Clear a cached token.
49
+ */
50
+ clearToken(cacheKey: TokenCacheKey): void;
51
+ /**
52
+ * Clear all cached tokens.
53
+ */
54
+ clearAllTokens(): void;
55
+ /**
56
+ * Handle authorization code callback (from browser redirect).
57
+ */
58
+ handleAuthorizationCallback(code: string | undefined, state: string | undefined, error?: string): void;
59
+ /**
60
+ * Handle implicit flow callback (from browser redirect with token in fragment).
61
+ */
62
+ handleImplicitCallback(accessToken: string, tokenType: string | undefined, expiresIn: number | undefined, state: string | undefined): void;
63
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * OAuth2 Token Manager
3
+ *
4
+ * Platform-independent implementation of OAuth2 token lifecycle management:
5
+ * - Token caching with expiration
6
+ * - PKCE (S256 / plain) challenge generation
7
+ * - Authorization Code flow via system browser + URI handler callback
8
+ * - Implicit flow via system browser
9
+ * - Client Credentials and Password grant token fetching
10
+ * - Token refresh with automatic retry
11
+ * - Secure storage for refresh tokens via ISecretStore
12
+ *
13
+ * Platform-specific behaviour (browser opening, secret storage, callback URIs)
14
+ * is injected via IExternalBrowserService and ISecretStore interfaces.
15
+ */
16
+ import { IEnvironmentConfigService } from '../environment/interfaces';
17
+ import { IHttpRequestService } from '../http/interfaces';
18
+ import { IExternalBrowserService, ISecretStore } from '../types/platform';
19
+ import { OAuth2Config } from '../types/types';
20
+ import { IOAuth2TokenManager, TokenCacheKey, TokenInfo } from './interfaces';
21
+ export declare class OAuth2TokenManager implements IOAuth2TokenManager {
22
+ private readonly secretStore;
23
+ private readonly browserService;
24
+ private readonly envConfigService;
25
+ private readonly httpService;
26
+ private readonly callbackPath;
27
+ private tokenCache;
28
+ /**
29
+ * Pending authorization-code resolve/reject.
30
+ * Set when we launch the browser; resolved when the URI handler fires.
31
+ */
32
+ private pendingAuthCallback;
33
+ /**
34
+ * Pending implicit-flow resolve/reject.
35
+ */
36
+ private pendingImplicitCallback;
37
+ /**
38
+ * @param secretStore Secure storage for refresh tokens (wraps vscode.SecretStorage, keytar, etc.)
39
+ * @param browserService External browser interaction (wraps vscode.env.openExternal, etc.)
40
+ * @param envConfigService Environment variable resolution
41
+ * @param httpService HTTP client for token endpoint calls
42
+ * @param callbackPath Platform-specific callback path (e.g. "henry-huang.http-forge/oauth2/callback")
43
+ */
44
+ constructor(secretStore: ISecretStore, browserService: IExternalBrowserService, envConfigService: IEnvironmentConfigService, httpService: IHttpRequestService, callbackPath?: string);
45
+ /**
46
+ * Get a valid token — uses cache, refresh, or full re-auth as needed.
47
+ */
48
+ getToken(config: OAuth2Config, environment: string): Promise<TokenInfo>;
49
+ /**
50
+ * Refresh an existing token.
51
+ */
52
+ refreshToken(config: OAuth2Config, currentRefreshToken: string, environment: string): Promise<TokenInfo>;
53
+ /**
54
+ * Authorization Code + PKCE flow.
55
+ *
56
+ * 1. Generate code_verifier & code_challenge (S256)
57
+ * 2. Open system browser with authorize URL
58
+ * 3. Wait for URI handler callback with ?code=xxx&state=yyy
59
+ * 4. Exchange code + code_verifier for token
60
+ */
61
+ authorizationCodeFlow(config: OAuth2Config, environment: string): Promise<TokenInfo>;
62
+ /**
63
+ * Implicit flow — opens browser, waits for hash fragment with access_token.
64
+ * Since the URI handler receives query params (not fragments), a small
65
+ * redirect page is needed to convert fragment → query. We handle both cases.
66
+ */
67
+ implicitFlow(config: OAuth2Config, environment: string): Promise<TokenInfo>;
68
+ /**
69
+ * Called by the URI handler when browser redirects back.
70
+ * Handles both authorization_code (?code=) and implicit (?access_token=) callbacks.
71
+ */
72
+ handleAuthorizationCallback(code: string | undefined, state: string | undefined, error?: string): void;
73
+ /**
74
+ * Handle implicit callback with access_token directly.
75
+ */
76
+ handleImplicitCallback(accessToken: string, tokenType: string | undefined, expiresIn: number | undefined, state: string | undefined): void;
77
+ clearToken(cacheKey: TokenCacheKey): void;
78
+ clearAllTokens(): void;
79
+ /**
80
+ * Fetch token using client_credentials or password grant.
81
+ */
82
+ private fetchToken;
83
+ /**
84
+ * Apply client authentication to the request (body or Basic Auth header).
85
+ */
86
+ private applyClientAuth;
87
+ /**
88
+ * Parse token endpoint response body into TokenInfo.
89
+ */
90
+ private parseTokenResponse;
91
+ private isExpired;
92
+ private buildCacheKeyString;
93
+ /**
94
+ * Get the callback URI for OAuth2 redirects.
95
+ * Uses the browser service to create a valid, externally accessible callback URI.
96
+ */
97
+ private getCallbackUri;
98
+ /** Resolve environment variables in a string */
99
+ private resolve;
100
+ private generateCodeVerifier;
101
+ private generateCodeChallengeS256;
102
+ private storeRefreshToken;
103
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Collection Loader Factory
3
+ *
4
+ * Factory Pattern: Creates appropriate loader based on configuration
5
+ */
6
+ import { IConfigService } from '../config';
7
+ import { ICollectionStore } from './collection-store';
8
+ /**
9
+ * Factory for creating collection loaders
10
+ */
11
+ export declare class CollectionLoaderFactory {
12
+ /**
13
+ * Create a collection loader based on configuration
14
+ */
15
+ static create(configService: IConfigService): ICollectionStore;
16
+ /**
17
+ * Create a loader for a specific format
18
+ */
19
+ static createForFormat(format: 'folder' | 'json', collectionsPath: string): ICollectionStore;
20
+ }
@@ -4,8 +4,9 @@
4
4
  * Single Responsibility: Load collections from file system
5
5
  * Dependency Inversion: Uses IFileSystem and ParserRegistry abstractions
6
6
  */
7
- import { ICollectionLoader, IFileSystem } from '../interfaces';
8
- import { UnifiedCollection } from '../interfaces/types';
7
+ import { IFileSystem } from '../types/platform';
8
+ import { UnifiedCollection } from '../types/types';
9
+ import { ICollectionLoader } from './interfaces';
9
10
  import { ParserRegistry } from './parser-registry';
10
11
  /**
11
12
  * Options for loading a collection
@@ -49,4 +50,3 @@ export declare class CollectionLoader implements ICollectionLoader {
49
50
  */
50
51
  getSupportedFormats(): string[];
51
52
  }
52
- //# sourceMappingURL=collection-loader.d.ts.map
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Collection Service Interface
3
+ *
4
+ * Interface Segregation: Separated into focused sub-interfaces
5
+ * Dependency Inversion: Consumers depend on this abstraction
6
+ */
7
+ import { CollectionRequest, KeyValueEntry, RequestAuth, RequestScripts, RequestSettings } from '../types/types';
8
+ export type { CollectionRequest, KeyValueEntry, RequestAuth, RequestScripts, RequestSettings };
9
+ /**
10
+ * Request item in a collection - CollectionRequest with type discriminator
11
+ */
12
+ export type CollectionRequestItem = CollectionRequest & {
13
+ type: 'request';
14
+ };
15
+ /**
16
+ * Folder item in a collection
17
+ */
18
+ export interface CollectionFolderItem {
19
+ type: 'folder';
20
+ id: string;
21
+ name: string;
22
+ description?: string;
23
+ auth?: RequestAuth;
24
+ scripts?: RequestScripts;
25
+ items?: CollectionItem[];
26
+ }
27
+ /**
28
+ * Collection item - discriminated union of request or folder
29
+ */
30
+ export type CollectionItem = CollectionRequestItem | CollectionFolderItem;
31
+ /**
32
+ * Collection definition
33
+ */
34
+ export interface Collection {
35
+ id: string;
36
+ name: string;
37
+ description?: string;
38
+ version?: string;
39
+ variables?: Record<string, string>;
40
+ auth?: RequestAuth;
41
+ scripts?: RequestScripts;
42
+ items: CollectionItem[];
43
+ }
44
+ /**
45
+ * Options for creating a request in a collection
46
+ */
47
+ export type CreateRequestOptions = Omit<CollectionRequest, 'id'> & {
48
+ collectionId: string;
49
+ parentId?: string;
50
+ id?: string;
51
+ };
52
+ /**
53
+ * Options for creating a folder
54
+ */
55
+ export interface CreateFolderOptions {
56
+ name: string;
57
+ collectionId: string;
58
+ parentId?: string;
59
+ }
60
+ /**
61
+ * Read-only collection operations
62
+ */
63
+ export interface ICollectionReader {
64
+ getAllCollections(): Collection[];
65
+ getCollection(id: string): Collection | undefined;
66
+ getCollectionById(id: string): Collection | undefined;
67
+ getCollectionByName(name: string): Collection | undefined;
68
+ findRequest(collectionId: string, requestId: string): CollectionRequestItem | undefined;
69
+ getCollectionVariables(collectionId: string): Record<string, string>;
70
+ }
71
+ /**
72
+ * Collection modification operations
73
+ */
74
+ export interface ICollectionWriter {
75
+ createCollection(name: string): Promise<Collection>;
76
+ saveCollection(collection: Collection): Promise<void>;
77
+ deleteCollection(id: string): Promise<boolean>;
78
+ renameCollection(id: string, newName: string): Promise<boolean>;
79
+ }
80
+ /**
81
+ * Request management operations
82
+ */
83
+ export interface IRequestManager {
84
+ createRequest(options: CreateRequestOptions): Promise<CollectionItem>;
85
+ updateRequest(collectionId: string, requestId: string, updates: Partial<CollectionItem>): Promise<boolean>;
86
+ deleteRequest(collectionId: string, requestId: string): Promise<boolean>;
87
+ renameRequest(collectionId: string, requestId: string, newName: string): Promise<boolean>;
88
+ }
89
+ /**
90
+ * Folder management operations
91
+ */
92
+ export interface IFolderManager {
93
+ createFolder(options: CreateFolderOptions): Promise<CollectionItem>;
94
+ deleteFolder(collectionId: string, folderId: string): Promise<boolean>;
95
+ renameFolder(collectionId: string, folderId: string, newName: string): Promise<boolean>;
96
+ }
97
+ /**
98
+ * Collection variable management
99
+ */
100
+ export interface ICollectionVariableManager {
101
+ setCollectionVariable(collectionId: string, key: string, value: unknown): void;
102
+ deleteCollectionVariable(collectionId: string, key: string): void;
103
+ clearCollectionVariables(collectionId: string): void;
104
+ getCollectionVariableLocals(collectionId: string): Record<string, string>;
105
+ }
106
+ /**
107
+ * Collection import/export operations
108
+ */
109
+ export interface ICollectionImportExport {
110
+ importCollection(filePath: string): Promise<Collection>;
111
+ exportCollection(id: string, filePath: string): Promise<void>;
112
+ exportCollectionAsRestClientFolder(id: string, outDir: string): Promise<void>;
113
+ }
114
+ /**
115
+ * Full collection service interface
116
+ */
117
+ export interface ICollectionService extends ICollectionReader, ICollectionWriter, IRequestManager, IFolderManager, ICollectionVariableManager, ICollectionImportExport {
118
+ dispose(): void;
119
+ }