@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,445 @@
1
+ // src/capture/session.ts
2
+ import { chromium } from 'playwright';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { shouldCapture } from './filter.js';
5
+ import { isDomainMatch } from './domain.js';
6
+ import { SkillGenerator } from '../skill/generator.js';
7
+ import { detectCaptcha } from '../auth/refresh.js';
8
+ import { verifyEndpoints } from './verifier.js';
9
+ import { signSkillFile } from '../skill/signing.js';
10
+ import { writeSkillFile } from '../skill/store.js';
11
+ import { AuthManager, getMachineId } from '../auth/manager.js';
12
+ import { deriveKey } from '../auth/crypto.js';
13
+ import { homedir } from 'node:os';
14
+ import { join } from 'node:path';
15
+ const APITAP_DIR = join(homedir(), '.apitap');
16
+ const MAX_ELEMENTS = 100;
17
+ const MAX_TEXT_LENGTH = 200;
18
+ const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
19
+ export class CaptureSession {
20
+ id;
21
+ browser = null;
22
+ page = null;
23
+ generators = new Map();
24
+ totalRequests = 0;
25
+ filteredRequests = 0;
26
+ targetUrl = '';
27
+ options;
28
+ captchaDetectedDomains = new Set();
29
+ recentEndpoints = [];
30
+ timeoutTimer = null;
31
+ expired = false;
32
+ closed = false;
33
+ constructor(options = {}) {
34
+ this.id = randomUUID();
35
+ this.options = options;
36
+ }
37
+ async start(url) {
38
+ if (this.closed)
39
+ throw new Error('Session already closed');
40
+ this.targetUrl = url.startsWith('http') ? url : `https://${url}`;
41
+ const headless = this.options.headless ?? true;
42
+ this.browser = await chromium.launch({ headless });
43
+ const context = await this.browser.newContext();
44
+ // Inject cached session cookies if available
45
+ try {
46
+ const authDir = this.options.authDir ?? APITAP_DIR;
47
+ const machineId = await getMachineId();
48
+ const authManager = new AuthManager(authDir, machineId);
49
+ const domain = new URL(this.targetUrl).hostname;
50
+ const cachedSession = await authManager.retrieveSession(domain);
51
+ if (cachedSession?.cookies?.length) {
52
+ await context.addCookies(cachedSession.cookies);
53
+ }
54
+ }
55
+ catch {
56
+ // Auth retrieval failed — proceed without cached session
57
+ }
58
+ this.page = await context.newPage();
59
+ this.setupResponseListener();
60
+ // Auto-timeout to prevent leaked browsers (unref so it doesn't block process exit)
61
+ const timeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
62
+ this.timeoutTimer = setTimeout(() => {
63
+ this.expired = true;
64
+ this.cleanup().catch(() => { });
65
+ }, timeoutMs);
66
+ if (this.timeoutTimer.unref)
67
+ this.timeoutTimer.unref();
68
+ await this.page.goto(this.targetUrl, { waitUntil: 'domcontentloaded' });
69
+ return this.takeSnapshot();
70
+ }
71
+ async interact(action) {
72
+ if (this.expired)
73
+ return { success: false, error: 'Session expired', snapshot: this.emptySnapshot() };
74
+ if (this.closed)
75
+ return { success: false, error: 'Session closed', snapshot: this.emptySnapshot() };
76
+ if (!this.page)
77
+ return { success: false, error: 'Session not started', snapshot: this.emptySnapshot() };
78
+ try {
79
+ switch (action.action) {
80
+ case 'snapshot':
81
+ return { success: true, snapshot: await this.takeSnapshot() };
82
+ case 'click': {
83
+ if (!action.ref)
84
+ return { success: false, error: 'ref required for click', snapshot: await this.takeSnapshot() };
85
+ const el = await this.resolveRef(action.ref);
86
+ if (!el)
87
+ return { success: false, error: `Element ${action.ref} not found`, snapshot: await this.takeSnapshot() };
88
+ await el.click();
89
+ await this.page.waitForLoadState('domcontentloaded').catch(() => { });
90
+ return { success: true, snapshot: await this.takeSnapshot() };
91
+ }
92
+ case 'type': {
93
+ if (!action.ref)
94
+ return { success: false, error: 'ref required for type', snapshot: await this.takeSnapshot() };
95
+ if (action.text === undefined)
96
+ return { success: false, error: 'text required for type', snapshot: await this.takeSnapshot() };
97
+ const el = await this.resolveRef(action.ref);
98
+ if (!el)
99
+ return { success: false, error: `Element ${action.ref} not found`, snapshot: await this.takeSnapshot() };
100
+ await el.fill(action.text);
101
+ if (action.submit) {
102
+ await el.press('Enter');
103
+ await this.page.waitForLoadState('domcontentloaded').catch(() => { });
104
+ }
105
+ return { success: true, snapshot: await this.takeSnapshot() };
106
+ }
107
+ case 'select': {
108
+ if (!action.ref)
109
+ return { success: false, error: 'ref required for select', snapshot: await this.takeSnapshot() };
110
+ if (action.value === undefined)
111
+ return { success: false, error: 'value required for select', snapshot: await this.takeSnapshot() };
112
+ const el = await this.resolveRef(action.ref);
113
+ if (!el)
114
+ return { success: false, error: `Element ${action.ref} not found`, snapshot: await this.takeSnapshot() };
115
+ await el.selectOption(action.value);
116
+ return { success: true, snapshot: await this.takeSnapshot() };
117
+ }
118
+ case 'navigate': {
119
+ if (!action.url)
120
+ return { success: false, error: 'url required for navigate', snapshot: await this.takeSnapshot() };
121
+ // Basic URL validation — block non-HTTP schemes and cloud metadata
122
+ let parsed;
123
+ try {
124
+ parsed = new URL(action.url);
125
+ }
126
+ catch {
127
+ return { success: false, error: 'Invalid URL', snapshot: await this.takeSnapshot() };
128
+ }
129
+ // Block non-HTTP schemes (file://, ftp://, etc.)
130
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
131
+ return { success: false, error: `Blocked scheme: ${parsed.protocol}`, snapshot: await this.takeSnapshot() };
132
+ }
133
+ // Block cloud metadata endpoint specifically (high-value target)
134
+ if (parsed.hostname === '169.254.169.254') {
135
+ return { success: false, error: 'Navigation blocked: cloud metadata endpoint', snapshot: await this.takeSnapshot() };
136
+ }
137
+ await this.page.goto(action.url, { waitUntil: 'domcontentloaded' });
138
+ return { success: true, snapshot: await this.takeSnapshot() };
139
+ }
140
+ case 'scroll': {
141
+ const dir = action.direction ?? 'down';
142
+ const delta = dir === 'up' ? -500 : 500;
143
+ await this.page.mouse.wheel(0, delta);
144
+ // Wait a bit for lazy-loaded content
145
+ await this.page.waitForTimeout(500);
146
+ return { success: true, snapshot: await this.takeSnapshot() };
147
+ }
148
+ case 'wait': {
149
+ const seconds = Math.min(action.seconds ?? 2, 10);
150
+ await this.page.waitForTimeout(seconds * 1000);
151
+ return { success: true, snapshot: await this.takeSnapshot() };
152
+ }
153
+ default:
154
+ return { success: false, error: `Unknown action: ${action.action}`, snapshot: await this.takeSnapshot() };
155
+ }
156
+ }
157
+ catch (err) {
158
+ // Try to return snapshot even on error
159
+ try {
160
+ return { success: false, error: err.message, snapshot: await this.takeSnapshot() };
161
+ }
162
+ catch {
163
+ return { success: false, error: err.message, snapshot: this.emptySnapshot() };
164
+ }
165
+ }
166
+ }
167
+ async finish() {
168
+ if (this.closed)
169
+ return { aborted: true, domains: [] };
170
+ // Measure DOM size before closing
171
+ let domBytes;
172
+ if (this.page) {
173
+ try {
174
+ const html = await this.page.content();
175
+ domBytes = html.length;
176
+ }
177
+ catch { /* page may have navigated away */ }
178
+ }
179
+ await this.cleanup();
180
+ // Mark captcha risk
181
+ for (const [hostname, gen] of this.generators) {
182
+ if (this.captchaDetectedDomains.has(hostname)) {
183
+ gen.setCaptchaRisk(true);
184
+ }
185
+ }
186
+ // Finalize: generate skill files, verify, sign, write
187
+ const machineId = await getMachineId();
188
+ const key = deriveKey(machineId);
189
+ const authManager = new AuthManager(APITAP_DIR, machineId);
190
+ const domains = [];
191
+ for (const [domain, generator] of this.generators) {
192
+ let skill = generator.toSkillFile(domain, {
193
+ domBytes,
194
+ totalRequests: this.totalRequests,
195
+ });
196
+ if (skill.endpoints.length === 0)
197
+ continue;
198
+ // Store extracted auth
199
+ const extractedAuth = generator.getExtractedAuth();
200
+ if (extractedAuth.length > 0) {
201
+ await authManager.store(domain, extractedAuth[0]);
202
+ }
203
+ // Store OAuth credentials if detected
204
+ const oauthConfig = generator.getOAuthConfig();
205
+ if (oauthConfig) {
206
+ const clientSecret = generator.getOAuthClientSecret();
207
+ if (clientSecret) {
208
+ await authManager.storeOAuthCredentials(domain, { clientSecret });
209
+ }
210
+ }
211
+ // Verify endpoints
212
+ skill = await verifyEndpoints(skill);
213
+ // Sign
214
+ skill = signSkillFile(skill, key);
215
+ // Write
216
+ const skillsDir = this.options.skillsDir;
217
+ const path = await writeSkillFile(skill, skillsDir);
218
+ // Tally tiers
219
+ const tiers = {};
220
+ for (const ep of skill.endpoints) {
221
+ const t = ep.replayability?.tier ?? 'unknown';
222
+ tiers[t] = (tiers[t] ?? 0) + 1;
223
+ }
224
+ domains.push({
225
+ domain,
226
+ endpointCount: skill.endpoints.length,
227
+ tiers,
228
+ skillFile: path,
229
+ });
230
+ }
231
+ return { aborted: false, domains };
232
+ }
233
+ async abort() {
234
+ await this.cleanup();
235
+ }
236
+ /** Whether session has been terminated (expired, closed, or aborted) */
237
+ get isActive() {
238
+ return !this.closed && !this.expired;
239
+ }
240
+ // --- private ---
241
+ setupResponseListener() {
242
+ if (!this.page)
243
+ return;
244
+ const generatorOptions = {
245
+ enablePreview: false,
246
+ scrub: true,
247
+ };
248
+ this.page.on('response', async (response) => {
249
+ this.totalRequests++;
250
+ const url = response.url();
251
+ const status = response.status();
252
+ const contentType = response.headers()['content-type'] ?? '';
253
+ // Domain filtering
254
+ if (!this.options.allDomains) {
255
+ const hostname = safeHostname(url);
256
+ if (hostname && !isDomainMatch(hostname, this.targetUrl)) {
257
+ this.filteredRequests++;
258
+ return;
259
+ }
260
+ }
261
+ if (!shouldCapture({ url, status, contentType })) {
262
+ this.filteredRequests++;
263
+ const hostname = safeHostname(url);
264
+ if (hostname) {
265
+ const gen = this.generators.get(hostname);
266
+ if (gen)
267
+ gen.recordFiltered();
268
+ }
269
+ // Track network bytes
270
+ const contentLength = parseInt(response.headers()['content-length'] ?? '0', 10);
271
+ if (contentLength > 0) {
272
+ const filteredHostname = safeHostname(url);
273
+ if (filteredHostname && this.generators.has(filteredHostname)) {
274
+ this.generators.get(filteredHostname).addNetworkBytes(contentLength);
275
+ }
276
+ }
277
+ return;
278
+ }
279
+ try {
280
+ const body = await response.text();
281
+ const hostname = new URL(url).hostname;
282
+ // Captcha detection
283
+ if (contentType.includes('text/html') && detectCaptcha(body)) {
284
+ this.captchaDetectedDomains.add(hostname);
285
+ }
286
+ if (!this.generators.has(hostname)) {
287
+ this.generators.set(hostname, new SkillGenerator(generatorOptions));
288
+ }
289
+ const gen = this.generators.get(hostname);
290
+ const exchange = {
291
+ request: {
292
+ url,
293
+ method: response.request().method(),
294
+ headers: response.request().headers(),
295
+ postData: response.request().postData() ?? undefined,
296
+ },
297
+ response: {
298
+ status,
299
+ headers: response.headers(),
300
+ body,
301
+ contentType,
302
+ },
303
+ timestamp: new Date().toISOString(),
304
+ };
305
+ const endpoint = gen.addExchange(exchange);
306
+ if (endpoint) {
307
+ const label = `${endpoint.method} ${endpoint.path}`;
308
+ this.recentEndpoints.push(label);
309
+ if (this.recentEndpoints.length > 5) {
310
+ this.recentEndpoints.shift();
311
+ }
312
+ }
313
+ }
314
+ catch {
315
+ // Response body may not be available
316
+ }
317
+ });
318
+ }
319
+ async takeSnapshot() {
320
+ if (!this.page)
321
+ return this.emptySnapshot();
322
+ try {
323
+ const url = this.page.url();
324
+ const title = await this.page.title();
325
+ const elements = await this.extractElements();
326
+ // Count unique endpoints across all generators
327
+ let endpointsCaptured = 0;
328
+ for (const gen of this.generators.values()) {
329
+ endpointsCaptured += gen.endpointCount;
330
+ }
331
+ return {
332
+ url,
333
+ title,
334
+ elements,
335
+ endpointsCaptured,
336
+ totalRequests: this.totalRequests,
337
+ filteredRequests: this.filteredRequests,
338
+ recentEndpoints: [...this.recentEndpoints],
339
+ };
340
+ }
341
+ catch {
342
+ return this.emptySnapshot();
343
+ }
344
+ }
345
+ async extractElements() {
346
+ if (!this.page)
347
+ return [];
348
+ return this.page.evaluate(({ maxElements, maxText }) => {
349
+ const selector = 'a[href], button, input, select, textarea, [role="button"], [role="link"], [onclick], [tabindex]';
350
+ const nodes = document.querySelectorAll(selector);
351
+ const results = [];
352
+ for (const node of nodes) {
353
+ if (results.length >= maxElements)
354
+ break;
355
+ const el = node;
356
+ // Skip hidden/tiny elements
357
+ const rect = el.getBoundingClientRect();
358
+ if (rect.width === 0 && rect.height === 0)
359
+ continue;
360
+ const style = window.getComputedStyle(el);
361
+ if (style.display === 'none' || style.visibility === 'hidden')
362
+ continue;
363
+ const tag = el.tagName.toLowerCase();
364
+ const text = (el.textContent || '').trim().slice(0, maxText);
365
+ const role = el.getAttribute('role') || undefined;
366
+ const name = el.name || undefined;
367
+ const placeholder = el.placeholder || undefined;
368
+ const href = el.href || undefined;
369
+ const type = el.type || undefined;
370
+ const disabled = el.disabled || undefined;
371
+ results.push({
372
+ ref: `e${results.length}`,
373
+ tag,
374
+ ...(role ? { role } : {}),
375
+ text,
376
+ ...(name ? { name } : {}),
377
+ ...(placeholder ? { placeholder } : {}),
378
+ ...(href ? { href } : {}),
379
+ ...(type ? { type } : {}),
380
+ ...(disabled ? { disabled } : {}),
381
+ });
382
+ }
383
+ return results;
384
+ }, { maxElements: MAX_ELEMENTS, maxText: MAX_TEXT_LENGTH });
385
+ }
386
+ async resolveRef(ref) {
387
+ if (!this.page)
388
+ return null;
389
+ const index = parseInt(ref.replace('e', ''), 10);
390
+ if (isNaN(index))
391
+ return null;
392
+ // Re-query the DOM to get the nth visible interactive element
393
+ const selector = 'a[href], button, input, select, textarea, [role="button"], [role="link"], [onclick], [tabindex]';
394
+ const elements = await this.page.$$(selector);
395
+ // Filter to visible elements
396
+ let visibleIndex = 0;
397
+ for (const el of elements) {
398
+ const visible = await el.isVisible().catch(() => false);
399
+ if (!visible)
400
+ continue;
401
+ if (visibleIndex === index) {
402
+ return el;
403
+ }
404
+ visibleIndex++;
405
+ }
406
+ return null;
407
+ }
408
+ emptySnapshot() {
409
+ return {
410
+ url: '',
411
+ title: '',
412
+ elements: [],
413
+ endpointsCaptured: 0,
414
+ totalRequests: this.totalRequests,
415
+ filteredRequests: this.filteredRequests,
416
+ recentEndpoints: [...this.recentEndpoints],
417
+ };
418
+ }
419
+ async cleanup() {
420
+ if (this.closed)
421
+ return;
422
+ this.closed = true;
423
+ if (this.timeoutTimer) {
424
+ clearTimeout(this.timeoutTimer);
425
+ this.timeoutTimer = null;
426
+ }
427
+ if (this.browser) {
428
+ try {
429
+ await this.browser.close();
430
+ }
431
+ catch { /* already closed */ }
432
+ this.browser = null;
433
+ this.page = null;
434
+ }
435
+ }
436
+ }
437
+ function safeHostname(url) {
438
+ try {
439
+ return new URL(url).hostname;
440
+ }
441
+ catch {
442
+ return null;
443
+ }
444
+ }
445
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/capture/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Check if a name/value pair represents a refreshable session token.
3
+ *
4
+ * @param name - Field name (e.g., "csrf_token", "nonce")
5
+ * @param value - Field value
6
+ * @returns true if this is a refreshable token
7
+ */
8
+ export declare function isRefreshableToken(name: string, value: string): boolean;
9
+ /**
10
+ * Scan a request body for refreshable tokens.
11
+ *
12
+ * @param body - Parsed request body (object or string)
13
+ * @param prefix - JSON path prefix for nested objects
14
+ * @returns Array of JSON paths to refreshable tokens (e.g., ["csrf_token", "data.nonce"])
15
+ */
16
+ export declare function detectRefreshableTokens(body: unknown, prefix?: string): string[];
@@ -0,0 +1,62 @@
1
+ // src/capture/token-detector.ts
2
+ /**
3
+ * Token Detection for Auth Refresh
4
+ *
5
+ * Identifies tokens in request bodies that are:
6
+ * 1. Session-generated (CSRF, nonces) — need refresh via browser
7
+ * 2. NOT user credentials (access tokens, API keys) — should not auto-refresh
8
+ *
9
+ * Detection uses pattern matching on names and value heuristics (hex, base64).
10
+ */
11
+ // Token name patterns that indicate session-generated values
12
+ const TOKEN_NAME_PATTERNS = /csrf|token|nonce|xsrf|_token$/i;
13
+ // Exclude user-provided credentials (should not auto-refresh)
14
+ const TOKEN_NAME_EXCLUDE = /access.?token|auth.?token|api.?token|bearer/i;
15
+ // Token value patterns (high-entropy session tokens)
16
+ const TOKEN_VALUE_HEX = /^[a-f0-9]{32,64}$/i;
17
+ const TOKEN_VALUE_BASE64 = /^[A-Za-z0-9+/]{20,}={0,2}$/;
18
+ /**
19
+ * Check if a name/value pair represents a refreshable session token.
20
+ *
21
+ * @param name - Field name (e.g., "csrf_token", "nonce")
22
+ * @param value - Field value
23
+ * @returns true if this is a refreshable token
24
+ */
25
+ export function isRefreshableToken(name, value) {
26
+ // Must match token name pattern
27
+ if (!TOKEN_NAME_PATTERNS.test(name)) {
28
+ return false;
29
+ }
30
+ // Exclude user credentials
31
+ if (TOKEN_NAME_EXCLUDE.test(name)) {
32
+ return false;
33
+ }
34
+ // Value must look like a token (hex or base64, sufficient length)
35
+ const isHex = TOKEN_VALUE_HEX.test(value);
36
+ const isBase64 = TOKEN_VALUE_BASE64.test(value);
37
+ return isHex || isBase64;
38
+ }
39
+ /**
40
+ * Scan a request body for refreshable tokens.
41
+ *
42
+ * @param body - Parsed request body (object or string)
43
+ * @param prefix - JSON path prefix for nested objects
44
+ * @returns Array of JSON paths to refreshable tokens (e.g., ["csrf_token", "data.nonce"])
45
+ */
46
+ export function detectRefreshableTokens(body, prefix = '') {
47
+ const tokens = [];
48
+ if (typeof body !== 'object' || body === null) {
49
+ return tokens;
50
+ }
51
+ for (const [key, value] of Object.entries(body)) {
52
+ const path = prefix ? `${prefix}.${key}` : key;
53
+ if (typeof value === 'string' && isRefreshableToken(key, value)) {
54
+ tokens.push(path);
55
+ }
56
+ else if (typeof value === 'object' && value !== null) {
57
+ tokens.push(...detectRefreshableTokens(value, path));
58
+ }
59
+ }
60
+ return tokens;
61
+ }
62
+ //# sourceMappingURL=token-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-detector.js","sourceRoot":"","sources":["../../src/capture/token-detector.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAEhC;;;;;;;;GAQG;AAEH,6DAA6D;AAC7D,MAAM,mBAAmB,GAAG,gCAAgC,CAAC;AAE7D,8DAA8D;AAC9D,MAAM,kBAAkB,GAAG,8CAA8C,CAAC;AAE1E,qDAAqD;AACrD,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAC7C,MAAM,kBAAkB,GAAG,4BAA4B,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,KAAa;IAC5D,gCAAgC;IAChC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,2BAA2B;IAC3B,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kEAAkE;IAClE,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAEhD,OAAO,KAAK,IAAI,QAAQ,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,IAAa,EACb,MAAM,GAAG,EAAE;IAEX,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAC9C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAE/C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;YAChE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACvD,MAAM,CAAC,IAAI,CAAC,GAAG,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { SkillFile, SkillEndpoint, Replayability } from '../types.js';
2
+ /**
3
+ * Heuristic tier classification for non-GET endpoints (or when verification is skipped).
4
+ * Based on header analysis only.
5
+ */
6
+ export declare function classifyHeuristic(endpoint: SkillEndpoint): Replayability;
7
+ export interface VerifyOptions {
8
+ /** Verify POST/PUT/PATCH endpoints by replaying them (opt-in, may cause side effects). */
9
+ verifyPosts?: boolean;
10
+ }
11
+ /**
12
+ * Verify all GET endpoints in a skill file by replaying them.
13
+ * Non-GET endpoints get heuristic classification by default.
14
+ * With verifyPosts: true, POST/PUT/PATCH endpoints are also replayed.
15
+ * Returns a new skill file with replayability tags on all endpoints.
16
+ */
17
+ export declare function verifyEndpoints(skill: SkillFile, opts?: VerifyOptions): Promise<SkillFile>;