@apitap/core 1.0.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.
Files changed (236) hide show
  1. package/LICENSE +60 -0
  2. package/README.md +362 -0
  3. package/SKILL.md +270 -0
  4. package/dist/auth/crypto.d.ts +31 -0
  5. package/dist/auth/crypto.js +66 -0
  6. package/dist/auth/crypto.js.map +1 -0
  7. package/dist/auth/handoff.d.ts +29 -0
  8. package/dist/auth/handoff.js +180 -0
  9. package/dist/auth/handoff.js.map +1 -0
  10. package/dist/auth/manager.d.ts +46 -0
  11. package/dist/auth/manager.js +127 -0
  12. package/dist/auth/manager.js.map +1 -0
  13. package/dist/auth/oauth-refresh.d.ts +16 -0
  14. package/dist/auth/oauth-refresh.js +91 -0
  15. package/dist/auth/oauth-refresh.js.map +1 -0
  16. package/dist/auth/refresh.d.ts +43 -0
  17. package/dist/auth/refresh.js +217 -0
  18. package/dist/auth/refresh.js.map +1 -0
  19. package/dist/capture/anti-bot.d.ts +15 -0
  20. package/dist/capture/anti-bot.js +43 -0
  21. package/dist/capture/anti-bot.js.map +1 -0
  22. package/dist/capture/blocklist.d.ts +6 -0
  23. package/dist/capture/blocklist.js +70 -0
  24. package/dist/capture/blocklist.js.map +1 -0
  25. package/dist/capture/body-diff.d.ts +8 -0
  26. package/dist/capture/body-diff.js +102 -0
  27. package/dist/capture/body-diff.js.map +1 -0
  28. package/dist/capture/body-variables.d.ts +13 -0
  29. package/dist/capture/body-variables.js +142 -0
  30. package/dist/capture/body-variables.js.map +1 -0
  31. package/dist/capture/domain.d.ts +8 -0
  32. package/dist/capture/domain.js +34 -0
  33. package/dist/capture/domain.js.map +1 -0
  34. package/dist/capture/entropy.d.ts +33 -0
  35. package/dist/capture/entropy.js +100 -0
  36. package/dist/capture/entropy.js.map +1 -0
  37. package/dist/capture/filter.d.ts +11 -0
  38. package/dist/capture/filter.js +49 -0
  39. package/dist/capture/filter.js.map +1 -0
  40. package/dist/capture/graphql.d.ts +21 -0
  41. package/dist/capture/graphql.js +99 -0
  42. package/dist/capture/graphql.js.map +1 -0
  43. package/dist/capture/idle.d.ts +23 -0
  44. package/dist/capture/idle.js +44 -0
  45. package/dist/capture/idle.js.map +1 -0
  46. package/dist/capture/monitor.d.ts +26 -0
  47. package/dist/capture/monitor.js +183 -0
  48. package/dist/capture/monitor.js.map +1 -0
  49. package/dist/capture/oauth-detector.d.ts +18 -0
  50. package/dist/capture/oauth-detector.js +96 -0
  51. package/dist/capture/oauth-detector.js.map +1 -0
  52. package/dist/capture/pagination.d.ts +9 -0
  53. package/dist/capture/pagination.js +40 -0
  54. package/dist/capture/pagination.js.map +1 -0
  55. package/dist/capture/parameterize.d.ts +17 -0
  56. package/dist/capture/parameterize.js +63 -0
  57. package/dist/capture/parameterize.js.map +1 -0
  58. package/dist/capture/scrubber.d.ts +5 -0
  59. package/dist/capture/scrubber.js +38 -0
  60. package/dist/capture/scrubber.js.map +1 -0
  61. package/dist/capture/session.d.ts +46 -0
  62. package/dist/capture/session.js +445 -0
  63. package/dist/capture/session.js.map +1 -0
  64. package/dist/capture/token-detector.d.ts +16 -0
  65. package/dist/capture/token-detector.js +62 -0
  66. package/dist/capture/token-detector.js.map +1 -0
  67. package/dist/capture/verifier.d.ts +17 -0
  68. package/dist/capture/verifier.js +147 -0
  69. package/dist/capture/verifier.js.map +1 -0
  70. package/dist/cli.d.ts +2 -0
  71. package/dist/cli.js +930 -0
  72. package/dist/cli.js.map +1 -0
  73. package/dist/discovery/auth.d.ts +17 -0
  74. package/dist/discovery/auth.js +81 -0
  75. package/dist/discovery/auth.js.map +1 -0
  76. package/dist/discovery/fetch.d.ts +17 -0
  77. package/dist/discovery/fetch.js +59 -0
  78. package/dist/discovery/fetch.js.map +1 -0
  79. package/dist/discovery/frameworks.d.ts +11 -0
  80. package/dist/discovery/frameworks.js +249 -0
  81. package/dist/discovery/frameworks.js.map +1 -0
  82. package/dist/discovery/index.d.ts +21 -0
  83. package/dist/discovery/index.js +219 -0
  84. package/dist/discovery/index.js.map +1 -0
  85. package/dist/discovery/openapi.d.ts +13 -0
  86. package/dist/discovery/openapi.js +175 -0
  87. package/dist/discovery/openapi.js.map +1 -0
  88. package/dist/discovery/probes.d.ts +9 -0
  89. package/dist/discovery/probes.js +70 -0
  90. package/dist/discovery/probes.js.map +1 -0
  91. package/dist/index.d.ts +25 -0
  92. package/dist/index.js +25 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/inspect/report.d.ts +52 -0
  95. package/dist/inspect/report.js +191 -0
  96. package/dist/inspect/report.js.map +1 -0
  97. package/dist/mcp.d.ts +8 -0
  98. package/dist/mcp.js +526 -0
  99. package/dist/mcp.js.map +1 -0
  100. package/dist/orchestration/browse.d.ts +38 -0
  101. package/dist/orchestration/browse.js +198 -0
  102. package/dist/orchestration/browse.js.map +1 -0
  103. package/dist/orchestration/cache.d.ts +15 -0
  104. package/dist/orchestration/cache.js +24 -0
  105. package/dist/orchestration/cache.js.map +1 -0
  106. package/dist/plugin.d.ts +17 -0
  107. package/dist/plugin.js +158 -0
  108. package/dist/plugin.js.map +1 -0
  109. package/dist/read/decoders/deepwiki.d.ts +2 -0
  110. package/dist/read/decoders/deepwiki.js +148 -0
  111. package/dist/read/decoders/deepwiki.js.map +1 -0
  112. package/dist/read/decoders/grokipedia.d.ts +2 -0
  113. package/dist/read/decoders/grokipedia.js +210 -0
  114. package/dist/read/decoders/grokipedia.js.map +1 -0
  115. package/dist/read/decoders/hackernews.d.ts +2 -0
  116. package/dist/read/decoders/hackernews.js +168 -0
  117. package/dist/read/decoders/hackernews.js.map +1 -0
  118. package/dist/read/decoders/index.d.ts +2 -0
  119. package/dist/read/decoders/index.js +12 -0
  120. package/dist/read/decoders/index.js.map +1 -0
  121. package/dist/read/decoders/reddit.d.ts +2 -0
  122. package/dist/read/decoders/reddit.js +142 -0
  123. package/dist/read/decoders/reddit.js.map +1 -0
  124. package/dist/read/decoders/twitter.d.ts +12 -0
  125. package/dist/read/decoders/twitter.js +187 -0
  126. package/dist/read/decoders/twitter.js.map +1 -0
  127. package/dist/read/decoders/wikipedia.d.ts +2 -0
  128. package/dist/read/decoders/wikipedia.js +66 -0
  129. package/dist/read/decoders/wikipedia.js.map +1 -0
  130. package/dist/read/decoders/youtube.d.ts +2 -0
  131. package/dist/read/decoders/youtube.js +69 -0
  132. package/dist/read/decoders/youtube.js.map +1 -0
  133. package/dist/read/extract.d.ts +25 -0
  134. package/dist/read/extract.js +320 -0
  135. package/dist/read/extract.js.map +1 -0
  136. package/dist/read/index.d.ts +14 -0
  137. package/dist/read/index.js +66 -0
  138. package/dist/read/index.js.map +1 -0
  139. package/dist/read/peek.d.ts +9 -0
  140. package/dist/read/peek.js +137 -0
  141. package/dist/read/peek.js.map +1 -0
  142. package/dist/read/types.d.ts +44 -0
  143. package/dist/read/types.js +3 -0
  144. package/dist/read/types.js.map +1 -0
  145. package/dist/replay/engine.d.ts +53 -0
  146. package/dist/replay/engine.js +441 -0
  147. package/dist/replay/engine.js.map +1 -0
  148. package/dist/replay/truncate.d.ts +16 -0
  149. package/dist/replay/truncate.js +92 -0
  150. package/dist/replay/truncate.js.map +1 -0
  151. package/dist/serve.d.ts +31 -0
  152. package/dist/serve.js +149 -0
  153. package/dist/serve.js.map +1 -0
  154. package/dist/skill/generator.d.ts +44 -0
  155. package/dist/skill/generator.js +419 -0
  156. package/dist/skill/generator.js.map +1 -0
  157. package/dist/skill/importer.d.ts +26 -0
  158. package/dist/skill/importer.js +80 -0
  159. package/dist/skill/importer.js.map +1 -0
  160. package/dist/skill/search.d.ts +19 -0
  161. package/dist/skill/search.js +51 -0
  162. package/dist/skill/search.js.map +1 -0
  163. package/dist/skill/signing.d.ts +16 -0
  164. package/dist/skill/signing.js +34 -0
  165. package/dist/skill/signing.js.map +1 -0
  166. package/dist/skill/ssrf.d.ts +27 -0
  167. package/dist/skill/ssrf.js +210 -0
  168. package/dist/skill/ssrf.js.map +1 -0
  169. package/dist/skill/store.d.ts +7 -0
  170. package/dist/skill/store.js +93 -0
  171. package/dist/skill/store.js.map +1 -0
  172. package/dist/stats/report.d.ts +26 -0
  173. package/dist/stats/report.js +157 -0
  174. package/dist/stats/report.js.map +1 -0
  175. package/dist/types.d.ts +214 -0
  176. package/dist/types.js +3 -0
  177. package/dist/types.js.map +1 -0
  178. package/package.json +58 -0
  179. package/src/auth/crypto.ts +92 -0
  180. package/src/auth/handoff.ts +229 -0
  181. package/src/auth/manager.ts +140 -0
  182. package/src/auth/oauth-refresh.ts +120 -0
  183. package/src/auth/refresh.ts +300 -0
  184. package/src/capture/anti-bot.ts +63 -0
  185. package/src/capture/blocklist.ts +75 -0
  186. package/src/capture/body-diff.ts +109 -0
  187. package/src/capture/body-variables.ts +156 -0
  188. package/src/capture/domain.ts +34 -0
  189. package/src/capture/entropy.ts +121 -0
  190. package/src/capture/filter.ts +56 -0
  191. package/src/capture/graphql.ts +124 -0
  192. package/src/capture/idle.ts +45 -0
  193. package/src/capture/monitor.ts +224 -0
  194. package/src/capture/oauth-detector.ts +106 -0
  195. package/src/capture/pagination.ts +49 -0
  196. package/src/capture/parameterize.ts +68 -0
  197. package/src/capture/scrubber.ts +49 -0
  198. package/src/capture/session.ts +502 -0
  199. package/src/capture/token-detector.ts +76 -0
  200. package/src/capture/verifier.ts +171 -0
  201. package/src/cli.ts +1031 -0
  202. package/src/discovery/auth.ts +99 -0
  203. package/src/discovery/fetch.ts +85 -0
  204. package/src/discovery/frameworks.ts +231 -0
  205. package/src/discovery/index.ts +256 -0
  206. package/src/discovery/openapi.ts +230 -0
  207. package/src/discovery/probes.ts +76 -0
  208. package/src/index.ts +26 -0
  209. package/src/inspect/report.ts +247 -0
  210. package/src/mcp.ts +618 -0
  211. package/src/orchestration/browse.ts +250 -0
  212. package/src/orchestration/cache.ts +37 -0
  213. package/src/plugin.ts +188 -0
  214. package/src/read/decoders/deepwiki.ts +180 -0
  215. package/src/read/decoders/grokipedia.ts +246 -0
  216. package/src/read/decoders/hackernews.ts +198 -0
  217. package/src/read/decoders/index.ts +15 -0
  218. package/src/read/decoders/reddit.ts +158 -0
  219. package/src/read/decoders/twitter.ts +211 -0
  220. package/src/read/decoders/wikipedia.ts +75 -0
  221. package/src/read/decoders/youtube.ts +75 -0
  222. package/src/read/extract.ts +396 -0
  223. package/src/read/index.ts +78 -0
  224. package/src/read/peek.ts +175 -0
  225. package/src/read/types.ts +37 -0
  226. package/src/replay/engine.ts +559 -0
  227. package/src/replay/truncate.ts +116 -0
  228. package/src/serve.ts +189 -0
  229. package/src/skill/generator.ts +473 -0
  230. package/src/skill/importer.ts +107 -0
  231. package/src/skill/search.ts +76 -0
  232. package/src/skill/signing.ts +36 -0
  233. package/src/skill/ssrf.ts +238 -0
  234. package/src/skill/store.ts +107 -0
  235. package/src/stats/report.ts +208 -0
  236. package/src/types.ts +233 -0
@@ -0,0 +1,53 @@
1
+ import type { SkillFile } from '../types.js';
2
+ import type { AuthManager } from '../auth/manager.js';
3
+ export interface ReplayOptions {
4
+ /** User-provided parameters for path, query, and body substitution */
5
+ params?: Record<string, string>;
6
+ /** Auth manager for token injection (optional) */
7
+ authManager?: AuthManager;
8
+ /** Domain for auth lookups (required if authManager provided) */
9
+ domain?: string;
10
+ /** Force token refresh before replay (requires authManager) */
11
+ fresh?: boolean;
12
+ /** Maximum response size in bytes. If set, truncates large responses. */
13
+ maxBytes?: number;
14
+ /** @internal Skip SSRF check — for testing only */
15
+ _skipSsrfCheck?: boolean;
16
+ }
17
+ export interface ReplayResult {
18
+ status: number;
19
+ headers: Record<string, string>;
20
+ data: unknown;
21
+ /** Whether tokens were refreshed during this replay */
22
+ refreshed?: boolean;
23
+ /** Whether the response was truncated to fit maxBytes */
24
+ truncated?: boolean;
25
+ }
26
+ /**
27
+ * Replay a captured API endpoint.
28
+ *
29
+ * @param skill - Skill file containing endpoint definitions
30
+ * @param endpointId - ID of the endpoint to replay
31
+ * @param optionsOrParams - Either ReplayOptions object or params directly (for backward compat)
32
+ */
33
+ export declare function replayEndpoint(skill: SkillFile, endpointId: string, optionsOrParams?: ReplayOptions | Record<string, string>): Promise<ReplayResult>;
34
+ export interface BatchReplayRequest {
35
+ domain: string;
36
+ endpointId: string;
37
+ params?: Record<string, string>;
38
+ }
39
+ export interface BatchReplayResult {
40
+ domain: string;
41
+ endpointId: string;
42
+ status: number;
43
+ data: unknown;
44
+ error?: string;
45
+ tier?: string;
46
+ capturedAt?: string;
47
+ truncated?: boolean;
48
+ }
49
+ export declare function replayMultiple(requests: BatchReplayRequest[], options?: {
50
+ skillsDir?: string;
51
+ maxBytes?: number;
52
+ _skipSsrfCheck?: boolean;
53
+ }): Promise<BatchReplayResult[]>;
@@ -0,0 +1,441 @@
1
+ import { substituteBodyVariables } from '../capture/body-variables.js';
2
+ import { parseJwtClaims } from '../capture/entropy.js';
3
+ import { refreshTokens } from '../auth/refresh.js';
4
+ import { truncateResponse } from './truncate.js';
5
+ import { resolveAndValidateUrl } from '../skill/ssrf.js';
6
+ // Header security: prevent header injection from skill files
7
+ const ALLOWED_SKILL_HEADERS = new Set([
8
+ 'accept', 'accept-language', 'accept-encoding',
9
+ 'content-type', 'content-length',
10
+ 'x-requested-with', 'x-api-key',
11
+ 'origin', 'referer',
12
+ 'user-agent',
13
+ // Auth headers are injected separately from encrypted storage, not from skill file
14
+ ]);
15
+ const BLOCKED_HEADERS = new Set([
16
+ 'host', 'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto',
17
+ 'x-real-ip', 'forwarded', 'via',
18
+ 'cookie', 'set-cookie',
19
+ 'authorization', // Must come from auth manager, not skill file
20
+ 'proxy-authorization',
21
+ 'transfer-encoding', 'te', 'trailer',
22
+ 'connection', 'upgrade',
23
+ ]);
24
+ /**
25
+ * Extract default path param values from an example URL by comparing
26
+ * it to the parameterized path template.
27
+ */
28
+ function extractPathDefaults(pathTemplate, exampleUrl) {
29
+ const defaults = {};
30
+ try {
31
+ const examplePath = new URL(exampleUrl).pathname;
32
+ const templateParts = pathTemplate.split('/');
33
+ const exampleParts = examplePath.split('/');
34
+ for (let i = 0; i < templateParts.length && i < exampleParts.length; i++) {
35
+ if (templateParts[i].startsWith(':')) {
36
+ const paramName = templateParts[i].slice(1);
37
+ defaults[paramName] = exampleParts[i];
38
+ }
39
+ }
40
+ }
41
+ catch {
42
+ // Invalid example URL — no defaults
43
+ }
44
+ return defaults;
45
+ }
46
+ /**
47
+ * Substitute :param placeholders in a path with values.
48
+ */
49
+ function substitutePath(pathTemplate, params) {
50
+ return pathTemplate.replace(/:([a-zA-Z_]+)/g, (match, name) => {
51
+ return params[name] ?? match;
52
+ });
53
+ }
54
+ /**
55
+ * Detect if options object is new-style ReplayOptions or legacy params.
56
+ * ReplayOptions has keys like authManager, domain, fresh, or params.
57
+ * Legacy params only have string values.
58
+ */
59
+ function normalizeOptions(optionsOrParams) {
60
+ if (!optionsOrParams) {
61
+ return {};
62
+ }
63
+ // Check for ReplayOptions signature (has known option keys or non-string values)
64
+ const hasOptionKeys = 'authManager' in optionsOrParams ||
65
+ 'domain' in optionsOrParams ||
66
+ 'fresh' in optionsOrParams ||
67
+ 'params' in optionsOrParams ||
68
+ 'maxBytes' in optionsOrParams ||
69
+ '_skipSsrfCheck' in optionsOrParams;
70
+ if (hasOptionKeys) {
71
+ return optionsOrParams;
72
+ }
73
+ // Legacy: treat entire object as params
74
+ return { params: optionsOrParams };
75
+ }
76
+ /**
77
+ * Wrap a 401/403 response with structured auth guidance.
78
+ */
79
+ function wrapAuthError(status, originalData, domain) {
80
+ if (status !== 401 && status !== 403)
81
+ return originalData;
82
+ return {
83
+ status,
84
+ error: 'Authentication required',
85
+ suggestion: `Use apitap_auth_request to log in to ${domain}`,
86
+ domain,
87
+ originalResponse: originalData,
88
+ };
89
+ }
90
+ /**
91
+ * Replay a captured API endpoint.
92
+ *
93
+ * @param skill - Skill file containing endpoint definitions
94
+ * @param endpointId - ID of the endpoint to replay
95
+ * @param optionsOrParams - Either ReplayOptions object or params directly (for backward compat)
96
+ */
97
+ export async function replayEndpoint(skill, endpointId, optionsOrParams) {
98
+ // Normalize options: support both new ReplayOptions and legacy params-only
99
+ const options = normalizeOptions(optionsOrParams);
100
+ const { params = {}, authManager, domain } = options;
101
+ const endpoint = skill.endpoints.find(e => e.id === endpointId);
102
+ if (!endpoint) {
103
+ throw new Error(`Endpoint "${endpointId}" not found in skill for ${skill.domain}. ` +
104
+ `Available: ${skill.endpoints.map(e => e.id).join(', ')}`);
105
+ }
106
+ // Resolve path: substitute :param placeholders
107
+ let resolvedPath = endpoint.path;
108
+ if (resolvedPath.includes(':')) {
109
+ const defaults = extractPathDefaults(endpoint.path, endpoint.examples.request.url);
110
+ const merged = { ...defaults, ...params };
111
+ resolvedPath = substitutePath(resolvedPath, merged);
112
+ }
113
+ const url = new URL(resolvedPath, skill.baseUrl);
114
+ // Apply query params: start with captured defaults, override with provided params
115
+ for (const [key, val] of Object.entries(endpoint.queryParams)) {
116
+ url.searchParams.set(key, val.example);
117
+ }
118
+ if (params) {
119
+ for (const [key, val] of Object.entries(params)) {
120
+ // Skip path params (already handled above)
121
+ if (endpoint.path.includes(`:${key}`))
122
+ continue;
123
+ // Skip body variables (they have dots in the path)
124
+ if (key.includes('.'))
125
+ continue;
126
+ url.searchParams.set(key, val);
127
+ }
128
+ }
129
+ // SSRF validation — block requests to private/internal IPs and get resolved URL
130
+ let fetchUrl = url.toString();
131
+ if (!options._skipSsrfCheck) {
132
+ const ssrfCheck = await resolveAndValidateUrl(url.toString());
133
+ if (!ssrfCheck.safe) {
134
+ throw new Error(`SSRF blocked: ${ssrfCheck.reason}`);
135
+ }
136
+ // Use resolved IP to prevent DNS rebinding
137
+ if (ssrfCheck.resolvedUrl) {
138
+ fetchUrl = ssrfCheck.resolvedUrl;
139
+ }
140
+ }
141
+ // Prepare request body if present
142
+ let body;
143
+ const headers = { ...endpoint.headers };
144
+ // Filter headers from skill file — block dangerous headers
145
+ for (const key of Object.keys(headers)) {
146
+ const lower = key.toLowerCase();
147
+ if (BLOCKED_HEADERS.has(lower) || (!ALLOWED_SKILL_HEADERS.has(lower) && !lower.startsWith('x-'))) {
148
+ delete headers[key];
149
+ }
150
+ }
151
+ // If using DNS-pinned URL, preserve original Host header
152
+ if (fetchUrl !== url.toString()) {
153
+ headers['host'] = url.hostname;
154
+ }
155
+ // Inject auth header from auth manager (if available)
156
+ if (authManager && domain) {
157
+ const auth = await authManager.retrieve(domain);
158
+ if (auth && auth.header && auth.value) {
159
+ headers[auth.header] = auth.value;
160
+ }
161
+ }
162
+ if (endpoint.requestBody) {
163
+ let processedBody = endpoint.requestBody.template;
164
+ // Inject refreshable tokens from storage (v0.8)
165
+ if (authManager && domain && endpoint.requestBody.refreshableTokens?.length) {
166
+ const storedTokens = await authManager.retrieveTokens(domain);
167
+ if (storedTokens) {
168
+ const tokenValues = {};
169
+ for (const tokenName of endpoint.requestBody.refreshableTokens) {
170
+ if (storedTokens[tokenName]) {
171
+ tokenValues[tokenName] = storedTokens[tokenName].value;
172
+ }
173
+ }
174
+ if (Object.keys(tokenValues).length > 0) {
175
+ processedBody = substituteBodyVariables(processedBody, tokenValues);
176
+ }
177
+ }
178
+ }
179
+ // Substitute user-provided variables
180
+ if (params && endpoint.requestBody.variables) {
181
+ processedBody = substituteBodyVariables(processedBody, params);
182
+ }
183
+ // Serialize to string
184
+ if (typeof processedBody === 'object') {
185
+ body = JSON.stringify(processedBody);
186
+ }
187
+ else {
188
+ body = processedBody;
189
+ }
190
+ // Ensure content-type is set
191
+ if (!headers['content-type']) {
192
+ headers['content-type'] = endpoint.requestBody.contentType;
193
+ }
194
+ }
195
+ // Proactive JWT expiry check: skip doomed request if token is expired
196
+ const fresh = options.fresh ?? false;
197
+ let refreshed = false;
198
+ if (authManager && domain) {
199
+ if (fresh) {
200
+ // --fresh flag: force refresh before replay
201
+ const refreshResult = await refreshTokens(skill, authManager, { domain, _skipSsrfCheck: options._skipSsrfCheck });
202
+ if (refreshResult.success) {
203
+ refreshed = true;
204
+ // Re-inject fresh auth header
205
+ const freshAuth = await authManager.retrieve(domain);
206
+ if (freshAuth) {
207
+ headers[freshAuth.header] = freshAuth.value;
208
+ }
209
+ }
210
+ }
211
+ else {
212
+ // Proactive: check if JWT is expired (30s buffer for clock skew)
213
+ const currentAuth = await authManager.retrieve(domain);
214
+ if (currentAuth?.value) {
215
+ const raw = currentAuth.value.startsWith('Bearer ')
216
+ ? currentAuth.value.slice(7)
217
+ : currentAuth.value;
218
+ const jwt = parseJwtClaims(raw);
219
+ if (jwt?.exp && jwt.exp < Math.floor(Date.now() / 1000) + 30) {
220
+ const refreshResult = await refreshTokens(skill, authManager, { domain, _skipSsrfCheck: options._skipSsrfCheck });
221
+ if (refreshResult.success) {
222
+ refreshed = true;
223
+ const freshAuth = await authManager.retrieve(domain);
224
+ if (freshAuth) {
225
+ headers[freshAuth.header] = freshAuth.value;
226
+ }
227
+ }
228
+ }
229
+ }
230
+ }
231
+ }
232
+ let response = await fetch(fetchUrl, {
233
+ method: endpoint.method,
234
+ headers,
235
+ body,
236
+ signal: AbortSignal.timeout(30_000),
237
+ redirect: 'manual', // Don't auto-follow redirects
238
+ });
239
+ // Handle redirects with SSRF validation (single hop only)
240
+ if (response.status >= 300 && response.status < 400) {
241
+ const location = response.headers.get('location');
242
+ if (location) {
243
+ const redirectUrl = new URL(location, url);
244
+ let redirectFetchUrl = redirectUrl.toString();
245
+ if (!options._skipSsrfCheck) {
246
+ const redirectCheck = await resolveAndValidateUrl(redirectUrl.toString());
247
+ if (!redirectCheck.safe) {
248
+ throw new Error(`Redirect blocked (SSRF): ${redirectCheck.reason}`);
249
+ }
250
+ if (redirectCheck.resolvedUrl) {
251
+ redirectFetchUrl = redirectCheck.resolvedUrl;
252
+ headers['host'] = redirectUrl.hostname;
253
+ }
254
+ }
255
+ // Follow the redirect manually (single hop to prevent chains)
256
+ response = await fetch(redirectFetchUrl, {
257
+ method: 'GET', // Redirects typically become GET
258
+ headers, // Forward headers (already filtered)
259
+ signal: AbortSignal.timeout(30_000),
260
+ redirect: 'manual', // Prevent chaining
261
+ });
262
+ }
263
+ }
264
+ // Reactive: retry on 401/403 if we haven't already refreshed
265
+ if ((response.status === 401 || response.status === 403) &&
266
+ !refreshed &&
267
+ authManager &&
268
+ domain) {
269
+ const refreshResult = await refreshTokens(skill, authManager, { domain, _skipSsrfCheck: options._skipSsrfCheck });
270
+ if (refreshResult.success) {
271
+ refreshed = true;
272
+ // Re-inject fresh auth
273
+ const freshAuth = await authManager.retrieve(domain);
274
+ if (freshAuth) {
275
+ headers[freshAuth.header] = freshAuth.value;
276
+ }
277
+ // Retry the request
278
+ let retryResponse = await fetch(fetchUrl, {
279
+ method: endpoint.method,
280
+ headers,
281
+ body,
282
+ signal: AbortSignal.timeout(30_000),
283
+ redirect: 'manual',
284
+ });
285
+ // Handle redirects on retry (single hop)
286
+ if (retryResponse.status >= 300 && retryResponse.status < 400) {
287
+ const location = retryResponse.headers.get('location');
288
+ if (location) {
289
+ const redirectUrl = new URL(location, url);
290
+ let retryRedirectFetchUrl = redirectUrl.toString();
291
+ if (!options._skipSsrfCheck) {
292
+ const redirectCheck = await resolveAndValidateUrl(redirectUrl.toString());
293
+ if (!redirectCheck.safe) {
294
+ throw new Error(`Redirect blocked (SSRF): ${redirectCheck.reason}`);
295
+ }
296
+ if (redirectCheck.resolvedUrl) {
297
+ retryRedirectFetchUrl = redirectCheck.resolvedUrl;
298
+ headers['host'] = redirectUrl.hostname;
299
+ }
300
+ }
301
+ retryResponse = await fetch(retryRedirectFetchUrl, {
302
+ method: 'GET',
303
+ headers,
304
+ signal: AbortSignal.timeout(30_000),
305
+ redirect: 'manual',
306
+ });
307
+ }
308
+ }
309
+ const retryHeaders = {};
310
+ retryResponse.headers.forEach((value, key) => {
311
+ retryHeaders[key] = value;
312
+ });
313
+ let retryData;
314
+ const retryCt = retryResponse.headers.get('content-type') ?? '';
315
+ const retryText = await retryResponse.text();
316
+ if (retryCt.includes('json') && retryText.length > 0) {
317
+ retryData = JSON.parse(retryText);
318
+ }
319
+ else {
320
+ retryData = retryText;
321
+ }
322
+ const retryFinalData = (retryResponse.status === 401 || retryResponse.status === 403)
323
+ ? wrapAuthError(retryResponse.status, retryData, skill.domain)
324
+ : retryData;
325
+ if (options.maxBytes) {
326
+ const truncated = truncateResponse(retryFinalData, { maxBytes: options.maxBytes });
327
+ return {
328
+ status: retryResponse.status,
329
+ headers: retryHeaders,
330
+ data: truncated.data,
331
+ refreshed,
332
+ ...(truncated.truncated ? { truncated: true } : {}),
333
+ };
334
+ }
335
+ return {
336
+ status: retryResponse.status,
337
+ headers: retryHeaders,
338
+ data: retryFinalData,
339
+ refreshed,
340
+ };
341
+ }
342
+ }
343
+ const responseHeaders = {};
344
+ response.headers.forEach((value, key) => {
345
+ responseHeaders[key] = value;
346
+ });
347
+ let data;
348
+ const ct = response.headers.get('content-type') ?? '';
349
+ const text = await response.text();
350
+ if (ct.includes('json') && text.length > 0) {
351
+ data = JSON.parse(text);
352
+ }
353
+ else {
354
+ data = text;
355
+ }
356
+ const finalData = (response.status === 401 || response.status === 403)
357
+ ? wrapAuthError(response.status, data, skill.domain)
358
+ : data;
359
+ // Apply truncation if maxBytes is set
360
+ if (options.maxBytes) {
361
+ const truncated = truncateResponse(finalData, { maxBytes: options.maxBytes });
362
+ return {
363
+ status: response.status,
364
+ headers: responseHeaders,
365
+ data: truncated.data,
366
+ ...(refreshed ? { refreshed } : {}),
367
+ ...(truncated.truncated ? { truncated: true } : {}),
368
+ };
369
+ }
370
+ return { status: response.status, headers: responseHeaders, data: finalData, ...(refreshed ? { refreshed } : {}) };
371
+ }
372
+ export async function replayMultiple(requests, options = {}) {
373
+ if (requests.length === 0)
374
+ return [];
375
+ const { readSkillFile } = await import('../skill/store.js');
376
+ const { AuthManager, getMachineId } = await import('../auth/manager.js');
377
+ // Deduplicate skill file reads
378
+ const skillCache = new Map();
379
+ const uniqueDomains = [...new Set(requests.map(r => r.domain))];
380
+ await Promise.all(uniqueDomains.map(async (domain) => {
381
+ const skill = await readSkillFile(domain, options.skillsDir);
382
+ skillCache.set(domain, skill);
383
+ }));
384
+ // Shared auth manager
385
+ const machineId = await getMachineId();
386
+ const authManager = new AuthManager((await import('node:os')).homedir() + '/.apitap', machineId);
387
+ // Replay all in parallel
388
+ const settled = await Promise.allSettled(requests.map(async (req) => {
389
+ const skill = skillCache.get(req.domain);
390
+ if (!skill) {
391
+ return {
392
+ domain: req.domain,
393
+ endpointId: req.endpointId,
394
+ status: 0,
395
+ data: null,
396
+ error: `No skill file found for "${req.domain}"`,
397
+ };
398
+ }
399
+ const endpoint = skill.endpoints.find(e => e.id === req.endpointId);
400
+ const tier = endpoint?.replayability?.tier ?? 'unknown';
401
+ try {
402
+ const result = await replayEndpoint(skill, req.endpointId, {
403
+ params: req.params,
404
+ authManager,
405
+ domain: req.domain,
406
+ maxBytes: options.maxBytes,
407
+ _skipSsrfCheck: options._skipSsrfCheck,
408
+ });
409
+ return {
410
+ domain: req.domain,
411
+ endpointId: req.endpointId,
412
+ status: result.status,
413
+ data: result.data,
414
+ tier,
415
+ capturedAt: skill.capturedAt,
416
+ ...(result.truncated ? { truncated: true } : {}),
417
+ };
418
+ }
419
+ catch (err) {
420
+ return {
421
+ domain: req.domain,
422
+ endpointId: req.endpointId,
423
+ status: 0,
424
+ data: null,
425
+ error: err.message,
426
+ tier,
427
+ capturedAt: skill.capturedAt,
428
+ };
429
+ }
430
+ }));
431
+ return settled.map((s) => s.status === 'fulfilled'
432
+ ? s.value
433
+ : {
434
+ domain: '',
435
+ endpointId: '',
436
+ status: 0,
437
+ data: null,
438
+ error: s.reason?.message ?? 'Unknown error',
439
+ });
440
+ }
441
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/replay/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface TruncateOptions {
2
+ maxBytes?: number;
3
+ }
4
+ export interface TruncateResult {
5
+ data: unknown;
6
+ truncated: boolean;
7
+ }
8
+ /**
9
+ * Truncate a response to fit within maxBytes when serialized as JSON.
10
+ *
11
+ * - Arrays: remove items from the end until it fits. If a single item
12
+ * exceeds the limit, truncate long string fields within that item.
13
+ * - Objects: truncate long string fields largest-first.
14
+ * - Primitives/strings: returned as-is (or sliced if string).
15
+ */
16
+ export declare function truncateResponse(data: unknown, options?: TruncateOptions): TruncateResult;
@@ -0,0 +1,92 @@
1
+ // src/replay/truncate.ts
2
+ const DEFAULT_MAX_BYTES = 50_000;
3
+ const STRING_CAP = 500;
4
+ function byteLength(s) {
5
+ return Buffer.byteLength(s, 'utf-8');
6
+ }
7
+ /**
8
+ * Truncate long string fields in an object, largest-first, until
9
+ * the serialized size is under maxBytes.
10
+ */
11
+ function truncateObjectStrings(obj, maxBytes) {
12
+ const result = { ...obj };
13
+ // Collect string fields with their lengths
14
+ const stringFields = [];
15
+ for (const [key, val] of Object.entries(result)) {
16
+ if (typeof val === 'string' && val.length > STRING_CAP) {
17
+ stringFields.push({ key, len: val.length });
18
+ }
19
+ }
20
+ // Sort largest first
21
+ stringFields.sort((a, b) => b.len - a.len);
22
+ for (const { key } of stringFields) {
23
+ const val = result[key];
24
+ result[key] = val.slice(0, STRING_CAP) + '... [truncated]';
25
+ if (byteLength(JSON.stringify(result)) <= maxBytes)
26
+ break;
27
+ }
28
+ return result;
29
+ }
30
+ /**
31
+ * Truncate a response to fit within maxBytes when serialized as JSON.
32
+ *
33
+ * - Arrays: remove items from the end until it fits. If a single item
34
+ * exceeds the limit, truncate long string fields within that item.
35
+ * - Objects: truncate long string fields largest-first.
36
+ * - Primitives/strings: returned as-is (or sliced if string).
37
+ */
38
+ export function truncateResponse(data, options) {
39
+ const maxBytes = options?.maxBytes ?? DEFAULT_MAX_BYTES;
40
+ if (data === null || data === undefined) {
41
+ return { data, truncated: false };
42
+ }
43
+ const serialized = JSON.stringify(data);
44
+ if (byteLength(serialized) <= maxBytes) {
45
+ return { data, truncated: false };
46
+ }
47
+ // Array truncation
48
+ if (Array.isArray(data)) {
49
+ const arr = [...data];
50
+ // Remove items from the end until it fits
51
+ while (arr.length > 1 && byteLength(JSON.stringify(arr)) > maxBytes) {
52
+ arr.pop();
53
+ }
54
+ // If single item still exceeds limit, truncate strings within it
55
+ if (arr.length === 1 && byteLength(JSON.stringify(arr)) > maxBytes) {
56
+ const item = arr[0];
57
+ if (item && typeof item === 'object' && !Array.isArray(item)) {
58
+ arr[0] = truncateObjectStrings(item, maxBytes);
59
+ }
60
+ }
61
+ // If still over (e.g. array of primitives), return empty array
62
+ if (arr.length === 1 && byteLength(JSON.stringify(arr)) > maxBytes) {
63
+ return { data: [], truncated: true };
64
+ }
65
+ return { data: arr, truncated: true };
66
+ }
67
+ // Object truncation
68
+ if (typeof data === 'object') {
69
+ const result = truncateObjectStrings(data, maxBytes);
70
+ return { data: result, truncated: true };
71
+ }
72
+ // String truncation as last resort
73
+ if (typeof data === 'string') {
74
+ // Binary search for the right length
75
+ let lo = 0;
76
+ let hi = data.length;
77
+ const suffix = '... [truncated]';
78
+ while (lo < hi) {
79
+ const mid = (lo + hi + 1) >> 1;
80
+ if (byteLength(JSON.stringify(data.slice(0, mid) + suffix)) <= maxBytes) {
81
+ lo = mid;
82
+ }
83
+ else {
84
+ hi = mid - 1;
85
+ }
86
+ }
87
+ return { data: data.slice(0, lo) + suffix, truncated: true };
88
+ }
89
+ // Numbers, booleans — can't truncate further
90
+ return { data, truncated: false };
91
+ }
92
+ //# sourceMappingURL=truncate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../../src/replay/truncate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { SkillFile } from './types.js';
3
+ export interface ServeTool {
4
+ name: string;
5
+ description: string;
6
+ endpointId: string;
7
+ inputSchema: {
8
+ type: 'object';
9
+ properties: Record<string, {
10
+ type: string;
11
+ description: string;
12
+ }>;
13
+ required: string[];
14
+ };
15
+ }
16
+ /**
17
+ * Build MCP tool definitions from a skill file's endpoints.
18
+ * Each endpoint becomes one tool named `domain_endpointId`.
19
+ */
20
+ export declare function buildServeTools(skill: SkillFile): ServeTool[];
21
+ export interface ServeOptions {
22
+ skillsDir?: string;
23
+ noAuth?: boolean;
24
+ /** @internal Skip SSRF validation — for testing only */
25
+ _skipSsrfCheck?: boolean;
26
+ }
27
+ /**
28
+ * Create an MCP server that exposes a skill file's endpoints as tools.
29
+ * Each endpoint becomes a callable tool that delegates to the replay engine.
30
+ */
31
+ export declare function createServeServer(domain: string, options?: ServeOptions): Promise<McpServer>;