capman 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/capman.js +221 -5
- package/dist/cjs/cache.d.ts +42 -0
- package/dist/cjs/cache.d.ts.map +1 -0
- package/dist/cjs/cache.js +179 -0
- package/dist/cjs/cache.js.map +1 -0
- package/dist/cjs/engine.d.ts +82 -0
- package/dist/cjs/engine.d.ts.map +1 -0
- package/dist/cjs/engine.js +233 -0
- package/dist/cjs/engine.js.map +1 -0
- package/dist/cjs/generator.js +2 -1
- package/dist/cjs/generator.js.map +1 -1
- package/dist/cjs/index.d.ts +7 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +13 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/learning.d.ts +56 -0
- package/dist/cjs/learning.d.ts.map +1 -0
- package/dist/cjs/learning.js +155 -0
- package/dist/cjs/learning.js.map +1 -0
- package/dist/cjs/matcher.d.ts.map +1 -1
- package/dist/cjs/matcher.js +38 -5
- package/dist/cjs/matcher.js.map +1 -1
- package/dist/cjs/resolver.d.ts +4 -1
- package/dist/cjs/resolver.d.ts.map +1 -1
- package/dist/cjs/resolver.js +51 -21
- package/dist/cjs/resolver.js.map +1 -1
- package/dist/cjs/schema.d.ts +10 -10
- package/dist/cjs/types.d.ts +38 -5
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/cjs/version.d.ts +2 -0
- package/dist/cjs/version.d.ts.map +1 -0
- package/dist/cjs/version.js +6 -0
- package/dist/cjs/version.js.map +1 -0
- package/dist/esm/cache.js +139 -0
- package/dist/esm/engine.js +228 -0
- package/dist/esm/generator.js +2 -1
- package/dist/esm/index.js +6 -0
- package/dist/esm/learning.js +116 -0
- package/dist/esm/matcher.js +38 -5
- package/dist/esm/resolver.js +51 -21
- package/dist/esm/version.js +2 -0
- package/package.json +18 -12
package/dist/esm/resolver.js
CHANGED
|
@@ -87,48 +87,78 @@ export async function resolve(matchResult, params = {}, options = {}) {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
async function resolveApi(resolver, params, options) {
|
|
90
|
+
const startTime = Date.now();
|
|
91
|
+
const retries = options.retries ?? 0;
|
|
92
|
+
const timeoutMs = options.timeoutMs ?? 5000;
|
|
90
93
|
const apiCalls = resolver.endpoints.map(endpoint => ({
|
|
91
94
|
method: endpoint.method,
|
|
92
95
|
url: buildUrl(options.baseUrl ?? '', endpoint.path, params),
|
|
93
96
|
params,
|
|
94
97
|
}));
|
|
95
98
|
if (options.dryRun) {
|
|
96
|
-
return { success: true, resolverType: 'api', apiCalls };
|
|
99
|
+
return { success: true, resolverType: 'api', apiCalls, durationMs: Date.now() - startTime };
|
|
97
100
|
}
|
|
98
101
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
99
102
|
if (!fetchFn) {
|
|
100
103
|
return {
|
|
101
|
-
success: true,
|
|
102
|
-
|
|
103
|
-
apiCalls,
|
|
104
|
+
success: true, resolverType: 'api', apiCalls,
|
|
105
|
+
durationMs: Date.now() - startTime,
|
|
104
106
|
error: 'No fetch available — returning call plan only',
|
|
105
107
|
};
|
|
106
108
|
}
|
|
109
|
+
// ── Fetch with retry + timeout ────────────────────────────────────────────
|
|
110
|
+
async function fetchWithRetry(call, attempt) {
|
|
111
|
+
const controller = new AbortController();
|
|
112
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
113
|
+
try {
|
|
114
|
+
const res = await fetchFn(call.url, {
|
|
115
|
+
method: call.method,
|
|
116
|
+
headers: options.headers ?? {},
|
|
117
|
+
signal: controller.signal,
|
|
118
|
+
body: ['POST', 'PUT', 'PATCH'].includes(call.method)
|
|
119
|
+
? JSON.stringify(call.params)
|
|
120
|
+
: undefined,
|
|
121
|
+
});
|
|
122
|
+
clearTimeout(timer);
|
|
123
|
+
return res;
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
const isTimeout = err instanceof Error && err.name === 'AbortError';
|
|
128
|
+
if (attempt < retries) {
|
|
129
|
+
logger.warn(`Request failed (attempt ${attempt + 1}/${retries + 1}) — retrying: ${isTimeout ? 'timeout' : err}`);
|
|
130
|
+
return fetchWithRetry(call, attempt + 1);
|
|
131
|
+
}
|
|
132
|
+
throw isTimeout ? new Error(`Request timed out after ${timeoutMs}ms`) : err;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
107
135
|
try {
|
|
108
|
-
const responses = await Promise.all(apiCalls.map(c =>
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
? JSON.stringify(c.params)
|
|
113
|
-
: undefined,
|
|
114
|
-
})));
|
|
115
|
-
// Check for HTTP errors
|
|
116
|
-
const failed = responses.find(r => !r.ok);
|
|
117
|
-
if (failed) {
|
|
136
|
+
const responses = await Promise.all(apiCalls.map(c => fetchWithRetry(c, 0)));
|
|
137
|
+
const failedIdx = responses.findIndex(r => !r.ok);
|
|
138
|
+
if (failedIdx !== -1) {
|
|
139
|
+
const failed = responses[failedIdx];
|
|
118
140
|
return {
|
|
119
|
-
success: false,
|
|
120
|
-
|
|
121
|
-
apiCalls,
|
|
141
|
+
success: false, resolverType: 'api', apiCalls,
|
|
142
|
+
durationMs: Date.now() - startTime,
|
|
122
143
|
error: `API request failed: ${failed.status} ${failed.statusText}`,
|
|
123
144
|
};
|
|
124
145
|
}
|
|
125
|
-
|
|
146
|
+
const enrichedCalls = await Promise.all(responses.map(async (res, i) => {
|
|
147
|
+
let data = undefined;
|
|
148
|
+
try {
|
|
149
|
+
const text = await res.text();
|
|
150
|
+
data = text ? JSON.parse(text) : undefined;
|
|
151
|
+
}
|
|
152
|
+
catch { /* non-JSON response */ }
|
|
153
|
+
return { ...apiCalls[i], status: res.status, data };
|
|
154
|
+
}));
|
|
155
|
+
logger.debug(`API calls completed in ${Date.now() - startTime}ms`);
|
|
156
|
+
return { success: true, resolverType: 'api', apiCalls: enrichedCalls, durationMs: Date.now() - startTime };
|
|
126
157
|
}
|
|
127
158
|
catch (err) {
|
|
128
159
|
return {
|
|
129
|
-
success: false,
|
|
130
|
-
|
|
131
|
-
apiCalls,
|
|
160
|
+
success: false, resolverType: 'api', apiCalls,
|
|
161
|
+
durationMs: Date.now() - startTime,
|
|
132
162
|
error: err instanceof Error ? err.message : String(err),
|
|
133
163
|
};
|
|
134
164
|
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "capman",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Capability Manifest Engine — let AI agents interact with your app without navigating the UI",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
7
7
|
"types": "./dist/cjs/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"import":
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/cjs/index.d.ts",
|
|
12
|
+
"default": "./dist/esm/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/cjs/index.d.ts",
|
|
16
|
+
"default": "./dist/cjs/index.js"
|
|
17
|
+
}
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"bin": {
|
|
@@ -22,14 +27,15 @@
|
|
|
22
27
|
"CONTRIBUTING.md"
|
|
23
28
|
],
|
|
24
29
|
"scripts": {
|
|
25
|
-
"
|
|
26
|
-
"build:
|
|
27
|
-
"build":
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
30
|
+
"prebuild": "node scripts/version.js",
|
|
31
|
+
"build:cjs": "tsc --project tsconfig.json",
|
|
32
|
+
"build:esm": "tsc --project tsconfig.esm.json",
|
|
33
|
+
"build": "pnpm run build:cjs && pnpm run build:esm",
|
|
34
|
+
"dev": "tsc --watch",
|
|
35
|
+
"example": "tsx examples/basic.ts",
|
|
36
|
+
"validate": "node bin/capman.js validate",
|
|
37
|
+
"inspect": "node bin/capman.js inspect",
|
|
38
|
+
"test": "vitest run"
|
|
33
39
|
},
|
|
34
40
|
"keywords": [
|
|
35
41
|
"ai",
|