@http-forge/core 0.4.2 → 0.4.4

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.
@@ -22,6 +22,8 @@ export declare class CollectionService implements ICollectionService {
22
22
  private collections;
23
23
  private fileWatcher?;
24
24
  private loader;
25
+ /** Debounce timer for coalescing rapid file-watcher change events */
26
+ private debounceTimer;
25
27
  /**
26
28
  * In-memory Local Values for collection variables (not persisted)
27
29
  */
@@ -49,6 +49,15 @@ export declare class FolderCollectionStore implements ICollectionStore {
49
49
  * Ensure collections directory exists
50
50
  */
51
51
  private ensureDirectory;
52
+ /**
53
+ * Read and parse a JSON metadata file, tolerating transient partial/empty reads.
54
+ *
55
+ * While another process writes files (e.g. importing a collection), a file watcher may
56
+ * trigger a load before the write completes, yielding empty or truncated content. Such
57
+ * cases are transient and expected, so they are skipped silently. Genuinely malformed
58
+ * (non-empty, complete) JSON is still reported.
59
+ */
60
+ private readJsonFileSafe;
52
61
  /**
53
62
  * Load all collections from disk
54
63
  */
@@ -26,9 +26,11 @@ export declare function runCollection(options: RunCollectionOptions): Promise<un
26
26
  * to `options.folderPath` (recursively by default). Returns the same result
27
27
  * shape as a collection run.
28
28
  */
29
- export declare function runFolder(options: RunCollectionOptions & {
29
+ export declare function runFolder(options: RunCollectionOptions & ({
30
30
  folderPath: string;
31
- }): Promise<unknown>;
31
+ } | {
32
+ folderRef: string;
33
+ })): Promise<unknown>;
32
34
  /**
33
35
  * Execute a test suite without MCP server overhead.
34
36
  * Returns typed result; never calls process.exit.
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Reference Resolver
3
+ *
4
+ * Resolves user-supplied collection / folder / request references that may be
5
+ * an id, a slug, or a display name. Resolution proceeds by tier in order
6
+ * (id -> slug -> name) and stops at the first tier that yields a match.
7
+ *
8
+ * - id : exact match against the immutable, canonical `id`.
9
+ * - slug : `generateSlug(name)` computed with sibling-ordered de-duplication
10
+ * (mirrors the on-disk directory/file naming).
11
+ * - name : case-insensitive match against the display `name`.
12
+ *
13
+ * A name (and, defensively, a slug) can match more than one sibling; when that
14
+ * happens an {@link AmbiguousRefError} is thrown carrying the candidate list so
15
+ * callers can present a clear disambiguation message instead of silently
16
+ * picking one.
17
+ *
18
+ * Used by the direct-execution run APIs to let the CLI address things with a
19
+ * single flag per concept.
20
+ */
21
+ import type { Collection, CollectionRequestItem } from '../types/collection';
22
+ /** Tier that produced a successful match. */
23
+ export type RefTier = 'id' | 'slug' | 'name';
24
+ /** Kind of reference being resolved (used for messaging). */
25
+ export type RefKind = 'collection' | 'folder' | 'request';
26
+ /** A candidate item surfaced when a reference is ambiguous. */
27
+ export interface RefCandidate {
28
+ id: string;
29
+ name: string;
30
+ /** Human-readable location (e.g. folder path) for disambiguation. */
31
+ path: string;
32
+ }
33
+ /** Information about how a reference was resolved (for transparency/logging). */
34
+ export interface ResolutionInfo {
35
+ kind: RefKind;
36
+ value: string;
37
+ tier: RefTier;
38
+ id: string;
39
+ path?: string;
40
+ }
41
+ /**
42
+ * Thrown when a reference value matches multiple items within the same scope.
43
+ */
44
+ export declare class AmbiguousRefError extends Error {
45
+ readonly kind: RefKind;
46
+ readonly value: string;
47
+ readonly candidates: RefCandidate[];
48
+ constructor(kind: RefKind, value: string, candidates: RefCandidate[]);
49
+ }
50
+ /**
51
+ * Resolve a collection reference (id, slug, or name) among all collections.
52
+ */
53
+ export declare function resolveCollectionRef(collections: Collection[], value: string): {
54
+ collection: Collection;
55
+ tier: RefTier;
56
+ };
57
+ /**
58
+ * Resolve a slash-separated folder reference into the folder-name path expected
59
+ * by the collection runner. Each segment is resolved id -> slug -> name against
60
+ * the folders at that level of the tree.
61
+ *
62
+ * @returns the resolved folder path (folder names joined by '/') and the tier
63
+ * that matched each segment.
64
+ */
65
+ export declare function resolveFolderRef(collection: Collection, slashPath: string): {
66
+ folderPath: string;
67
+ tiers: RefTier[];
68
+ };
69
+ /**
70
+ * Resolve a request reference (id, slug, or name) to a request id.
71
+ *
72
+ * When `folderPath` (folder names joined by '/') is provided, the search is
73
+ * scoped to that folder's subtree (recursively); otherwise the whole collection
74
+ * is searched. Ambiguous matches throw {@link AmbiguousRefError}.
75
+ */
76
+ export declare function resolveRequestRef(collection: Collection, value: string, folderPath?: string): {
77
+ request: CollectionRequestItem;
78
+ tier: RefTier;
79
+ folderPath: string;
80
+ };
@@ -9,6 +9,7 @@
9
9
  * 2. Direct execution: runRequest/runCollection/runSuite without MCP
10
10
  * 3. CLI: subcommands that use modes 1 and 2
11
11
  */
12
+ import type { ResolutionInfo } from './ref-resolver';
12
13
  /**
13
14
  * Configuration for creating an embeddable MCP runtime instance.
14
15
  */
@@ -47,10 +48,27 @@ export declare function createMcpRuntime(options: McpRuntimeOptions): Promise<Mc
47
48
  export interface RunRequestOptions {
48
49
  /** Workspace root folder path */
49
50
  workspaceFolder: string;
50
- /** Collection ID containing the request */
51
- collectionId: string;
52
- /** Request ID to execute */
53
- requestId: string;
51
+ /** Collection ID containing the request (exact id). */
52
+ collectionId?: string;
53
+ /** Request ID to execute (exact id). */
54
+ requestId?: string;
55
+ /**
56
+ * Collection reference resolved by tier id -> slug -> name. Used when an
57
+ * exact `collectionId` is not provided.
58
+ */
59
+ collectionRef?: string;
60
+ /**
61
+ * Request reference resolved by tier id -> slug -> name. Used when an exact
62
+ * `requestId` is not provided. Scoped to `folderRef` when that is provided.
63
+ */
64
+ requestRef?: string;
65
+ /**
66
+ * Optional folder reference (slash-separated id/slug/name segments) that
67
+ * scopes request resolution to that folder's subtree.
68
+ */
69
+ folderRef?: string;
70
+ /** Called for each reference resolved, for transparency/logging. */
71
+ onResolve?: (info: ResolutionInfo) => void;
54
72
  /** Environment name (defaults to currently selected) */
55
73
  environment?: string;
56
74
  /** Extra variables to inject into execution */
@@ -70,8 +88,20 @@ export interface RunRequestOptions {
70
88
  export interface RunCollectionOptions {
71
89
  /** Workspace root folder path */
72
90
  workspaceFolder: string;
73
- /** Collection ID to execute */
74
- collectionId: string;
91
+ /** Collection ID to execute (exact id). */
92
+ collectionId?: string;
93
+ /**
94
+ * Collection reference resolved by tier id -> slug -> name. Used when an
95
+ * exact `collectionId` is not provided.
96
+ */
97
+ collectionRef?: string;
98
+ /**
99
+ * Folder reference (slash-separated id/slug/name segments) resolved to a
100
+ * folder path. Used when an exact `folderPath` is not provided.
101
+ */
102
+ folderRef?: string;
103
+ /** Called for each reference resolved, for transparency/logging. */
104
+ onResolve?: (info: ResolutionInfo) => void;
75
105
  /** Environment name (defaults to currently selected) */
76
106
  environment?: string;
77
107
  /** Extra variables injected into every request */
@@ -130,12 +160,16 @@ export declare function runRequest(options: RunRequestOptions): Promise<unknown>
130
160
  export declare function runCollection(options: RunCollectionOptions): Promise<unknown>;
131
161
  /**
132
162
  * 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.
163
+ * server. Thin wrapper over {@link runCollection} scoped to a folder
164
+ * (recursively by default). The folder may be given as `folderPath` (folder
165
+ * names joined by '/') or `folderRef` (slash-separated id/slug/name segments).
166
+ * Returns the same result shape as a collection run.
135
167
  */
136
- export declare function runFolder(options: RunCollectionOptions & {
168
+ export declare function runFolder(options: RunCollectionOptions & ({
137
169
  folderPath: string;
138
- }): Promise<unknown>;
170
+ } | {
171
+ folderRef: string;
172
+ })): Promise<unknown>;
139
173
  /**
140
174
  * Execute a test suite directly without MCP server.
141
175
  * Returns typed result object; never calls process.exit.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@http-forge/core",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
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",