@wenathlan/saddle 1.8.17 → 2.0.2

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 (1005) hide show
  1. package/Dockerfile +1339 -0
  2. package/README.md +68 -22
  3. package/alternatives.ts +1218 -0
  4. package/biome.json +153 -0
  5. package/boards.json +1517 -0
  6. package/compute.ts +3144 -0
  7. package/cores.json +1801 -0
  8. package/dist/acquisition.d.ts +359 -0
  9. package/dist/acquisition.d.ts.map +1 -0
  10. package/dist/acquisition.js +629 -0
  11. package/dist/acquisition.js.map +1 -0
  12. package/dist/alternatives.d.ts +509 -0
  13. package/dist/alternatives.d.ts.map +1 -0
  14. package/dist/alternatives.js +951 -0
  15. package/dist/alternatives.js.map +1 -0
  16. package/dist/automation.d.ts +426 -0
  17. package/dist/automation.d.ts.map +1 -0
  18. package/dist/automation.js +561 -0
  19. package/dist/automation.js.map +1 -0
  20. package/dist/browser.d.ts +562 -0
  21. package/dist/browser.d.ts.map +1 -0
  22. package/dist/browser.js +1057 -0
  23. package/dist/browser.js.map +1 -0
  24. package/dist/capacitor.config.d.ts +13 -0
  25. package/dist/capacitor.config.d.ts.map +1 -0
  26. package/dist/capacitor.config.js +26 -0
  27. package/dist/capacitor.config.js.map +1 -0
  28. package/dist/cli.d.ts +17 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +111 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/communication.d.ts +192 -0
  33. package/dist/communication.d.ts.map +1 -0
  34. package/dist/communication.js +418 -0
  35. package/dist/communication.js.map +1 -0
  36. package/dist/compute.d.ts +1161 -0
  37. package/dist/compute.d.ts.map +1 -0
  38. package/dist/compute.js +2273 -0
  39. package/dist/compute.js.map +1 -0
  40. package/dist/distribution.d.ts +529 -0
  41. package/dist/distribution.d.ts.map +1 -0
  42. package/dist/distribution.js +811 -0
  43. package/dist/distribution.js.map +1 -0
  44. package/dist/execution.d.ts +530 -0
  45. package/dist/execution.d.ts.map +1 -0
  46. package/dist/execution.js +761 -0
  47. package/dist/execution.js.map +1 -0
  48. package/dist/format.d.ts +19 -0
  49. package/dist/format.d.ts.map +1 -0
  50. package/dist/format.js +60 -0
  51. package/dist/format.js.map +1 -0
  52. package/dist/foundation.d.ts +176 -0
  53. package/dist/foundation.d.ts.map +1 -0
  54. package/dist/foundation.js +309 -0
  55. package/dist/foundation.js.map +1 -0
  56. package/dist/index.d.ts +733 -122
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +1018 -122
  59. package/dist/index.js.map +1 -1
  60. package/dist/integration.d.ts +236 -0
  61. package/dist/integration.d.ts.map +1 -0
  62. package/dist/integration.js +236 -0
  63. package/dist/integration.js.map +1 -0
  64. package/dist/intelligence.d.ts +94 -0
  65. package/dist/intelligence.d.ts.map +1 -0
  66. package/dist/intelligence.js +145 -0
  67. package/dist/intelligence.js.map +1 -0
  68. package/dist/isolation.d.ts +129 -0
  69. package/dist/isolation.d.ts.map +1 -0
  70. package/dist/isolation.js +96 -0
  71. package/dist/isolation.js.map +1 -0
  72. package/dist/media.d.ts +344 -0
  73. package/dist/media.d.ts.map +1 -0
  74. package/dist/media.js +986 -0
  75. package/dist/media.js.map +1 -0
  76. package/dist/modes.d.ts +359 -0
  77. package/dist/modes.d.ts.map +1 -0
  78. package/dist/modes.js +134 -0
  79. package/dist/modes.js.map +1 -0
  80. package/dist/{library/public.d.ts → operations.d.ts} +15 -1
  81. package/dist/operations.d.ts.map +1 -0
  82. package/dist/{library/public.js → operations.js} +18 -7
  83. package/dist/operations.js.map +1 -0
  84. package/dist/orchestrator.d.ts +1339 -0
  85. package/dist/orchestrator.d.ts.map +1 -0
  86. package/dist/orchestrator.js +4308 -0
  87. package/dist/orchestrator.js.map +1 -0
  88. package/dist/performance.d.ts +416 -0
  89. package/dist/performance.d.ts.map +1 -0
  90. package/dist/performance.js +827 -0
  91. package/dist/performance.js.map +1 -0
  92. package/dist/quantum.d.ts +810 -0
  93. package/dist/quantum.d.ts.map +1 -0
  94. package/dist/quantum.js +2073 -0
  95. package/dist/quantum.js.map +1 -0
  96. package/dist/render.d.ts +381 -0
  97. package/dist/render.d.ts.map +1 -0
  98. package/dist/render.js +1073 -0
  99. package/dist/render.js.map +1 -0
  100. package/dist/scheduler.d.ts +596 -0
  101. package/dist/scheduler.d.ts.map +1 -0
  102. package/dist/scheduler.js +1259 -0
  103. package/dist/scheduler.js.map +1 -0
  104. package/dist/security.d.ts +501 -0
  105. package/dist/security.d.ts.map +1 -0
  106. package/dist/security.js +1170 -0
  107. package/dist/security.js.map +1 -0
  108. package/dist/server.d.ts +21 -0
  109. package/dist/server.d.ts.map +1 -0
  110. package/dist/{server/node.js → server.js} +16 -2
  111. package/dist/server.js.map +1 -0
  112. package/dist/tiers.d.ts +1002 -0
  113. package/dist/tiers.d.ts.map +1 -0
  114. package/dist/tiers.js +2165 -0
  115. package/dist/tiers.js.map +1 -0
  116. package/dist/virtual.d.ts +641 -0
  117. package/dist/virtual.d.ts.map +1 -0
  118. package/dist/virtual.js +1285 -0
  119. package/dist/virtual.js.map +1 -0
  120. package/dist/virtualcpu.d.ts +316 -0
  121. package/dist/virtualcpu.d.ts.map +1 -0
  122. package/dist/virtualcpu.js +1180 -0
  123. package/dist/virtualcpu.js.map +1 -0
  124. package/dist/virtualgpu.d.ts +345 -0
  125. package/dist/virtualgpu.d.ts.map +1 -0
  126. package/dist/virtualgpu.js +1000 -0
  127. package/dist/virtualgpu.js.map +1 -0
  128. package/dist/virtualization.d.ts +607 -0
  129. package/dist/virtualization.d.ts.map +1 -0
  130. package/dist/virtualization.js +1187 -0
  131. package/dist/virtualization.js.map +1 -0
  132. package/dist/virtualmemory.d.ts +818 -0
  133. package/dist/virtualmemory.d.ts.map +1 -0
  134. package/dist/virtualmemory.js +1796 -0
  135. package/dist/virtualmemory.js.map +1 -0
  136. package/dist/webscrape.d.ts +720 -0
  137. package/dist/webscrape.d.ts.map +1 -0
  138. package/dist/webscrape.js +2697 -0
  139. package/dist/webscrape.js.map +1 -0
  140. package/docker.config +769 -0
  141. package/docs/CONVERSA.txt +1523 -0
  142. package/docs/alternatives.md +499 -0
  143. package/docs/architecture-1.8.19.md +76 -0
  144. package/docs/architecture-1.8.19.mmd +33 -0
  145. package/docs/architecture-1.8.19.png +0 -0
  146. package/docs/architecture.md +355 -0
  147. package/docs/artifactavailability.md +6 -0
  148. package/docs/brancharchive-2026-08-18.md +18 -0
  149. package/docs/browser.md +7 -0
  150. package/docs/consolidation.md +70 -0
  151. package/docs/e2ugh-engine.md +528 -0
  152. package/{dist/examples/localjob.js → docs/example-localjob.ts} +3 -3
  153. package/{dist/examples/publicapi.js → docs/example-publicapi.ts} +2 -2
  154. package/docs/hardware.md +342 -0
  155. package/docs/optimization.md +126 -0
  156. package/docs/performance.md +499 -0
  157. package/docs/planning.1.8.18.md +94 -0
  158. package/docs/planning.1.8.19.md +49 -0
  159. package/docs/releasenotes-1.8.17.md +6 -0
  160. package/docs/releasenotes-1.8.18.md +32 -0
  161. package/docs/releasenotes-1.8.19.md +35 -0
  162. package/docs/research-1.8.18-isolation.md +43 -0
  163. package/docs/research-1.8.19-virtual-browser.md +27 -0
  164. package/docs/saddle.archive.1.8.17.tar.gz.gpg +0 -0
  165. package/docs/security.md +454 -0
  166. package/docs/todo-1.8.16.md +56 -1
  167. package/docs/todo-1.8.18.md +164 -0
  168. package/docs/todo-1.8.19.md +241 -0
  169. package/docs/viability.md +777 -0
  170. package/docs/virtualization.md +335 -0
  171. package/docs/web-duplicatecleanup.md +9 -0
  172. package/docs/web-ideas.md +106 -0
  173. package/docs/workflowimprovements-2026-08-19.md +70 -0
  174. package/gpumonitor.cpp +1543 -0
  175. package/gpus.json +2408 -0
  176. package/index.ts +1478 -0
  177. package/media.ts +1337 -0
  178. package/mttg.config +1549 -0
  179. package/orchestrator.ts +5462 -0
  180. package/package.json +304 -55
  181. package/passage.config +1331 -0
  182. package/performance.ts +1049 -0
  183. package/processors.json +2217 -0
  184. package/qemu.config +1062 -0
  185. package/qemubridge.py +1340 -0
  186. package/quantum.ts +2393 -0
  187. package/render.ts +1325 -0
  188. package/scheduler.ts +1600 -0
  189. package/security.ts +1449 -0
  190. package/tiers.ts +2871 -0
  191. package/tsconfig.json +29 -0
  192. package/virtualcpu.ts +1273 -0
  193. package/virtualgpu.ts +1181 -0
  194. package/virtualhardware.c +1011 -0
  195. package/virtualhardware.json +739 -0
  196. package/virtualization.ts +1628 -0
  197. package/virtualizationcore.cpp +4635 -0
  198. package/virtualmemory.ts +2303 -0
  199. package/vm.config.json +1910 -0
  200. package/{extension → web/extension}/manifest.json +1 -1
  201. package/web/readme.md +382 -0
  202. package/web/tsconfig.json +25 -0
  203. package/dist/adapters/forge.d.ts +0 -17
  204. package/dist/adapters/forge.d.ts.map +0 -1
  205. package/dist/adapters/forge.js +0 -19
  206. package/dist/adapters/forge.js.map +0 -1
  207. package/dist/adapters/forgejo.d.ts +0 -49
  208. package/dist/adapters/forgejo.d.ts.map +0 -1
  209. package/dist/adapters/forgejo.js +0 -8
  210. package/dist/adapters/forgejo.js.map +0 -1
  211. package/dist/adapters/github.d.ts +0 -12
  212. package/dist/adapters/github.d.ts.map +0 -1
  213. package/dist/adapters/github.js +0 -20
  214. package/dist/adapters/github.js.map +0 -1
  215. package/dist/adapters/gitlab.d.ts +0 -17
  216. package/dist/adapters/gitlab.d.ts.map +0 -1
  217. package/dist/adapters/gitlab.js +0 -10
  218. package/dist/adapters/gitlab.js.map +0 -1
  219. package/dist/adapters/huggingface.d.ts +0 -17
  220. package/dist/adapters/huggingface.d.ts.map +0 -1
  221. package/dist/adapters/huggingface.js +0 -6
  222. package/dist/adapters/huggingface.js.map +0 -1
  223. package/dist/adapters/socket.d.ts +0 -11
  224. package/dist/adapters/socket.d.ts.map +0 -1
  225. package/dist/adapters/socket.js +0 -17
  226. package/dist/adapters/socket.js.map +0 -1
  227. package/dist/adapters/transport.d.ts +0 -7
  228. package/dist/adapters/transport.d.ts.map +0 -1
  229. package/dist/adapters/transport.js +0 -36
  230. package/dist/adapters/transport.js.map +0 -1
  231. package/dist/ai/chunk.d.ts +0 -2
  232. package/dist/ai/chunk.d.ts.map +0 -1
  233. package/dist/ai/chunk.js +0 -36
  234. package/dist/ai/chunk.js.map +0 -1
  235. package/dist/ai/llmstxt.d.ts +0 -6
  236. package/dist/ai/llmstxt.d.ts.map +0 -1
  237. package/dist/ai/llmstxt.js +0 -12
  238. package/dist/ai/llmstxt.js.map +0 -1
  239. package/dist/ai/provenance.d.ts +0 -22
  240. package/dist/ai/provenance.d.ts.map +0 -1
  241. package/dist/ai/provenance.js +0 -25
  242. package/dist/ai/provenance.js.map +0 -1
  243. package/dist/ai/rag.d.ts +0 -26
  244. package/dist/ai/rag.d.ts.map +0 -1
  245. package/dist/ai/rag.js +0 -22
  246. package/dist/ai/rag.js.map +0 -1
  247. package/dist/ai/tokens.d.ts +0 -15
  248. package/dist/ai/tokens.d.ts.map +0 -1
  249. package/dist/ai/tokens.js +0 -9
  250. package/dist/ai/tokens.js.map +0 -1
  251. package/dist/api/auth.d.ts +0 -16
  252. package/dist/api/auth.d.ts.map +0 -1
  253. package/dist/api/auth.js +0 -19
  254. package/dist/api/auth.js.map +0 -1
  255. package/dist/api/contracts.d.ts +0 -28
  256. package/dist/api/contracts.d.ts.map +0 -1
  257. package/dist/api/contracts.js +0 -14
  258. package/dist/api/contracts.js.map +0 -1
  259. package/dist/api/control.d.ts +0 -10
  260. package/dist/api/control.d.ts.map +0 -1
  261. package/dist/api/control.js +0 -35
  262. package/dist/api/control.js.map +0 -1
  263. package/dist/api/http.d.ts +0 -7
  264. package/dist/api/http.d.ts.map +0 -1
  265. package/dist/api/http.js +0 -12
  266. package/dist/api/http.js.map +0 -1
  267. package/dist/api/rate.d.ts +0 -28
  268. package/dist/api/rate.d.ts.map +0 -1
  269. package/dist/api/rate.js +0 -36
  270. package/dist/api/rate.js.map +0 -1
  271. package/dist/api/security.d.ts +0 -12
  272. package/dist/api/security.d.ts.map +0 -1
  273. package/dist/api/security.js +0 -56
  274. package/dist/api/security.js.map +0 -1
  275. package/dist/api/service.d.ts +0 -5
  276. package/dist/api/service.d.ts.map +0 -1
  277. package/dist/api/service.js +0 -70
  278. package/dist/api/service.js.map +0 -1
  279. package/dist/apps/registry.d.ts +0 -33
  280. package/dist/apps/registry.d.ts.map +0 -1
  281. package/dist/apps/registry.js +0 -24
  282. package/dist/apps/registry.js.map +0 -1
  283. package/dist/binary/archive.d.ts +0 -27
  284. package/dist/binary/archive.d.ts.map +0 -1
  285. package/dist/binary/archive.js +0 -46
  286. package/dist/binary/archive.js.map +0 -1
  287. package/dist/binary/build.d.ts +0 -29
  288. package/dist/binary/build.d.ts.map +0 -1
  289. package/dist/binary/build.js +0 -17
  290. package/dist/binary/build.js.map +0 -1
  291. package/dist/binary/transform.d.ts +0 -70
  292. package/dist/binary/transform.d.ts.map +0 -1
  293. package/dist/binary/transform.js +0 -105
  294. package/dist/binary/transform.js.map +0 -1
  295. package/dist/bot/adapter.d.ts +0 -5
  296. package/dist/bot/adapter.d.ts.map +0 -1
  297. package/dist/bot/adapter.js +0 -11
  298. package/dist/bot/adapter.js.map +0 -1
  299. package/dist/bot/bot.d.ts +0 -28
  300. package/dist/bot/bot.d.ts.map +0 -1
  301. package/dist/bot/bot.js +0 -52
  302. package/dist/bot/bot.js.map +0 -1
  303. package/dist/bot/commands.d.ts +0 -8
  304. package/dist/bot/commands.d.ts.map +0 -1
  305. package/dist/bot/commands.js +0 -19
  306. package/dist/bot/commands.js.map +0 -1
  307. package/dist/bot/permissions.d.ts +0 -13
  308. package/dist/bot/permissions.d.ts.map +0 -1
  309. package/dist/bot/permissions.js +0 -16
  310. package/dist/bot/permissions.js.map +0 -1
  311. package/dist/browser/actions.d.ts +0 -33
  312. package/dist/browser/actions.d.ts.map +0 -1
  313. package/dist/browser/actions.js +0 -44
  314. package/dist/browser/actions.js.map +0 -1
  315. package/dist/browser/agent.d.ts +0 -21
  316. package/dist/browser/agent.d.ts.map +0 -1
  317. package/dist/browser/agent.js +0 -13
  318. package/dist/browser/agent.js.map +0 -1
  319. package/dist/browser/context.d.ts +0 -43
  320. package/dist/browser/context.d.ts.map +0 -1
  321. package/dist/browser/context.js +0 -54
  322. package/dist/browser/context.js.map +0 -1
  323. package/dist/browser/fingerprint.d.ts +0 -4
  324. package/dist/browser/fingerprint.d.ts.map +0 -1
  325. package/dist/browser/fingerprint.js +0 -12
  326. package/dist/browser/fingerprint.js.map +0 -1
  327. package/dist/browser/index.d.ts +0 -11
  328. package/dist/browser/index.d.ts.map +0 -1
  329. package/dist/browser/index.js +0 -11
  330. package/dist/browser/index.js.map +0 -1
  331. package/dist/browser/playwright.d.ts +0 -11
  332. package/dist/browser/playwright.d.ts.map +0 -1
  333. package/dist/browser/playwright.js +0 -24
  334. package/dist/browser/playwright.js.map +0 -1
  335. package/dist/browser/recorder.d.ts +0 -21
  336. package/dist/browser/recorder.d.ts.map +0 -1
  337. package/dist/browser/recorder.js +0 -58
  338. package/dist/browser/recorder.js.map +0 -1
  339. package/dist/browser/session.d.ts +0 -14
  340. package/dist/browser/session.d.ts.map +0 -1
  341. package/dist/browser/session.js +0 -21
  342. package/dist/browser/session.js.map +0 -1
  343. package/dist/browser/snapshot.d.ts +0 -69
  344. package/dist/browser/snapshot.d.ts.map +0 -1
  345. package/dist/browser/snapshot.js +0 -133
  346. package/dist/browser/snapshot.js.map +0 -1
  347. package/dist/captcha/contract.d.ts +0 -35
  348. package/dist/captcha/contract.d.ts.map +0 -1
  349. package/dist/captcha/contract.js +0 -17
  350. package/dist/captcha/contract.js.map +0 -1
  351. package/dist/captcha/evidence.d.ts +0 -10
  352. package/dist/captcha/evidence.d.ts.map +0 -1
  353. package/dist/captcha/evidence.js +0 -9
  354. package/dist/captcha/evidence.js.map +0 -1
  355. package/dist/captcha/guard.d.ts +0 -23
  356. package/dist/captcha/guard.d.ts.map +0 -1
  357. package/dist/captcha/guard.js +0 -12
  358. package/dist/captcha/guard.js.map +0 -1
  359. package/dist/cli/main.d.ts +0 -4
  360. package/dist/cli/main.d.ts.map +0 -1
  361. package/dist/cli/main.js +0 -46
  362. package/dist/cli/main.js.map +0 -1
  363. package/dist/core/errors.d.ts +0 -84
  364. package/dist/core/errors.d.ts.map +0 -1
  365. package/dist/core/errors.js +0 -54
  366. package/dist/core/errors.js.map +0 -1
  367. package/dist/core/events.d.ts +0 -9
  368. package/dist/core/events.d.ts.map +0 -1
  369. package/dist/core/events.js +0 -21
  370. package/dist/core/events.js.map +0 -1
  371. package/dist/core/hash.d.ts +0 -10
  372. package/dist/core/hash.d.ts.map +0 -1
  373. package/dist/core/hash.js +0 -82
  374. package/dist/core/hash.js.map +0 -1
  375. package/dist/core/ids.d.ts +0 -10
  376. package/dist/core/ids.d.ts.map +0 -1
  377. package/dist/core/ids.js +0 -15
  378. package/dist/core/ids.js.map +0 -1
  379. package/dist/delivery/manifest.d.ts +0 -35
  380. package/dist/delivery/manifest.d.ts.map +0 -1
  381. package/dist/delivery/manifest.js +0 -68
  382. package/dist/delivery/manifest.js.map +0 -1
  383. package/dist/deploy/index.d.ts +0 -6
  384. package/dist/deploy/index.d.ts.map +0 -1
  385. package/dist/deploy/index.js +0 -6
  386. package/dist/deploy/index.js.map +0 -1
  387. package/dist/dispatch/resumable.d.ts +0 -102
  388. package/dist/dispatch/resumable.d.ts.map +0 -1
  389. package/dist/dispatch/resumable.js +0 -64
  390. package/dist/dispatch/resumable.js.map +0 -1
  391. package/dist/dispatch/workflow.d.ts +0 -6
  392. package/dist/dispatch/workflow.d.ts.map +0 -1
  393. package/dist/dispatch/workflow.js +0 -37
  394. package/dist/dispatch/workflow.js.map +0 -1
  395. package/dist/domain/artifacts.d.ts +0 -12
  396. package/dist/domain/artifacts.d.ts.map +0 -1
  397. package/dist/domain/artifacts.js +0 -14
  398. package/dist/domain/artifacts.js.map +0 -1
  399. package/dist/domain/jobs.d.ts +0 -12
  400. package/dist/domain/jobs.d.ts.map +0 -1
  401. package/dist/domain/jobs.js +0 -20
  402. package/dist/domain/jobs.js.map +0 -1
  403. package/dist/domain/providers.d.ts +0 -10
  404. package/dist/domain/providers.d.ts.map +0 -1
  405. package/dist/domain/providers.js +0 -8
  406. package/dist/domain/providers.js.map +0 -1
  407. package/dist/domain/runtime.d.ts +0 -14
  408. package/dist/domain/runtime.d.ts.map +0 -1
  409. package/dist/domain/runtime.js +0 -10
  410. package/dist/domain/runtime.js.map +0 -1
  411. package/dist/domain/sessions.d.ts +0 -12
  412. package/dist/domain/sessions.d.ts.map +0 -1
  413. package/dist/domain/sessions.js +0 -57
  414. package/dist/domain/sessions.js.map +0 -1
  415. package/dist/examples/localjob.d.ts +0 -2
  416. package/dist/examples/localjob.d.ts.map +0 -1
  417. package/dist/examples/localjob.js.map +0 -1
  418. package/dist/examples/publicapi.d.ts +0 -2
  419. package/dist/examples/publicapi.d.ts.map +0 -1
  420. package/dist/examples/publicapi.js.map +0 -1
  421. package/dist/extension/build.d.ts +0 -9
  422. package/dist/extension/build.d.ts.map +0 -1
  423. package/dist/extension/build.js +0 -85
  424. package/dist/extension/build.js.map +0 -1
  425. package/dist/extension/content.d.ts +0 -6
  426. package/dist/extension/content.d.ts.map +0 -1
  427. package/dist/extension/content.js +0 -135
  428. package/dist/extension/content.js.map +0 -1
  429. package/dist/extension/index.d.ts +0 -7
  430. package/dist/extension/index.d.ts.map +0 -1
  431. package/dist/extension/index.js +0 -7
  432. package/dist/extension/index.js.map +0 -1
  433. package/dist/extension/pagebridge.d.ts +0 -6
  434. package/dist/extension/pagebridge.d.ts.map +0 -1
  435. package/dist/extension/pagebridge.js +0 -42
  436. package/dist/extension/pagebridge.js.map +0 -1
  437. package/dist/extension/permissions.d.ts +0 -26
  438. package/dist/extension/permissions.d.ts.map +0 -1
  439. package/dist/extension/permissions.js +0 -28
  440. package/dist/extension/permissions.js.map +0 -1
  441. package/dist/extension/popup.d.ts +0 -5
  442. package/dist/extension/popup.d.ts.map +0 -1
  443. package/dist/extension/popup.js +0 -26
  444. package/dist/extension/popup.js.map +0 -1
  445. package/dist/extension/protocol.d.ts +0 -58
  446. package/dist/extension/protocol.d.ts.map +0 -1
  447. package/dist/extension/protocol.js +0 -101
  448. package/dist/extension/protocol.js.map +0 -1
  449. package/dist/extension/serviceworker.d.ts +0 -25
  450. package/dist/extension/serviceworker.d.ts.map +0 -1
  451. package/dist/extension/serviceworker.js +0 -102
  452. package/dist/extension/serviceworker.js.map +0 -1
  453. package/dist/extension/worker.d.ts +0 -28
  454. package/dist/extension/worker.d.ts.map +0 -1
  455. package/dist/extension/worker.js +0 -22
  456. package/dist/extension/worker.js.map +0 -1
  457. package/dist/format/check.d.ts +0 -8
  458. package/dist/format/check.d.ts.map +0 -1
  459. package/dist/format/check.js +0 -38
  460. package/dist/format/check.js.map +0 -1
  461. package/dist/library/public.d.ts.map +0 -1
  462. package/dist/library/public.js.map +0 -1
  463. package/dist/mcp/browser.d.ts +0 -9
  464. package/dist/mcp/browser.d.ts.map +0 -1
  465. package/dist/mcp/browser.js +0 -13
  466. package/dist/mcp/browser.js.map +0 -1
  467. package/dist/mcp/server.d.ts +0 -35
  468. package/dist/mcp/server.d.ts.map +0 -1
  469. package/dist/mcp/server.js +0 -40
  470. package/dist/mcp/server.js.map +0 -1
  471. package/dist/mcp/transport.d.ts +0 -7
  472. package/dist/mcp/transport.d.ts.map +0 -1
  473. package/dist/mcp/transport.js +0 -17
  474. package/dist/mcp/transport.js.map +0 -1
  475. package/dist/memory/bridge.d.ts +0 -14
  476. package/dist/memory/bridge.d.ts.map +0 -1
  477. package/dist/memory/bridge.js +0 -16
  478. package/dist/memory/bridge.js.map +0 -1
  479. package/dist/memory/engine.d.ts +0 -38
  480. package/dist/memory/engine.d.ts.map +0 -1
  481. package/dist/memory/engine.js +0 -109
  482. package/dist/memory/engine.js.map +0 -1
  483. package/dist/memory/modes.d.ts +0 -43
  484. package/dist/memory/modes.d.ts.map +0 -1
  485. package/dist/memory/modes.js +0 -66
  486. package/dist/memory/modes.js.map +0 -1
  487. package/dist/memory/objects.d.ts +0 -21
  488. package/dist/memory/objects.d.ts.map +0 -1
  489. package/dist/memory/objects.js +0 -20
  490. package/dist/memory/objects.js.map +0 -1
  491. package/dist/memory/planner.d.ts +0 -66
  492. package/dist/memory/planner.d.ts.map +0 -1
  493. package/dist/memory/planner.js +0 -108
  494. package/dist/memory/planner.js.map +0 -1
  495. package/dist/memory/targets.d.ts +0 -78
  496. package/dist/memory/targets.d.ts.map +0 -1
  497. package/dist/memory/targets.js +0 -29
  498. package/dist/memory/targets.js.map +0 -1
  499. package/dist/memory/transforms.d.ts +0 -19
  500. package/dist/memory/transforms.d.ts.map +0 -1
  501. package/dist/memory/transforms.js +0 -14
  502. package/dist/memory/transforms.js.map +0 -1
  503. package/dist/modes/matrix.d.ts +0 -23
  504. package/dist/modes/matrix.d.ts.map +0 -1
  505. package/dist/modes/matrix.js +0 -18
  506. package/dist/modes/matrix.js.map +0 -1
  507. package/dist/modes/modes.d.ts +0 -33
  508. package/dist/modes/modes.d.ts.map +0 -1
  509. package/dist/modes/modes.js +0 -15
  510. package/dist/modes/modes.js.map +0 -1
  511. package/dist/modes/resolve.d.ts +0 -96
  512. package/dist/modes/resolve.d.ts.map +0 -1
  513. package/dist/modes/resolve.js +0 -48
  514. package/dist/modes/resolve.js.map +0 -1
  515. package/dist/observability/metrics.d.ts +0 -14
  516. package/dist/observability/metrics.d.ts.map +0 -1
  517. package/dist/observability/metrics.js +0 -18
  518. package/dist/observability/metrics.js.map +0 -1
  519. package/dist/packager/manifest.d.ts +0 -66
  520. package/dist/packager/manifest.d.ts.map +0 -1
  521. package/dist/packager/manifest.js +0 -94
  522. package/dist/packager/manifest.js.map +0 -1
  523. package/dist/packager/publish.d.ts +0 -51
  524. package/dist/packager/publish.d.ts.map +0 -1
  525. package/dist/packager/publish.js +0 -18
  526. package/dist/packager/publish.js.map +0 -1
  527. package/dist/packager/targetcli.d.ts +0 -7
  528. package/dist/packager/targetcli.d.ts.map +0 -1
  529. package/dist/packager/targetcli.js +0 -22
  530. package/dist/packager/targetcli.js.map +0 -1
  531. package/dist/persistence/adapter.d.ts +0 -5
  532. package/dist/persistence/adapter.d.ts.map +0 -1
  533. package/dist/persistence/adapter.js +0 -11
  534. package/dist/persistence/adapter.js.map +0 -1
  535. package/dist/persistence/drizzle.d.ts +0 -2
  536. package/dist/persistence/drizzle.d.ts.map +0 -1
  537. package/dist/persistence/drizzle.js +0 -12
  538. package/dist/persistence/drizzle.js.map +0 -1
  539. package/dist/persistence/memory.d.ts +0 -2
  540. package/dist/persistence/memory.d.ts.map +0 -1
  541. package/dist/persistence/memory.js +0 -27
  542. package/dist/persistence/memory.js.map +0 -1
  543. package/dist/persistence/migrations.d.ts +0 -19
  544. package/dist/persistence/migrations.d.ts.map +0 -1
  545. package/dist/persistence/migrations.js +0 -13
  546. package/dist/persistence/migrations.js.map +0 -1
  547. package/dist/persistence/prisma.d.ts +0 -2
  548. package/dist/persistence/prisma.d.ts.map +0 -1
  549. package/dist/persistence/prisma.js +0 -25
  550. package/dist/persistence/prisma.js.map +0 -1
  551. package/dist/persistence/schema.d.ts +0 -63
  552. package/dist/persistence/schema.d.ts.map +0 -1
  553. package/dist/persistence/schema.js +0 -28
  554. package/dist/persistence/schema.js.map +0 -1
  555. package/dist/persistence/sql.d.ts +0 -3
  556. package/dist/persistence/sql.d.ts.map +0 -1
  557. package/dist/persistence/sql.js +0 -37
  558. package/dist/persistence/sql.js.map +0 -1
  559. package/dist/protocol/blocks.d.ts +0 -10
  560. package/dist/protocol/blocks.d.ts.map +0 -1
  561. package/dist/protocol/blocks.js +0 -26
  562. package/dist/protocol/blocks.js.map +0 -1
  563. package/dist/protocol/json.d.ts +0 -6
  564. package/dist/protocol/json.d.ts.map +0 -1
  565. package/dist/protocol/json.js +0 -6
  566. package/dist/protocol/json.js.map +0 -1
  567. package/dist/protocol/ndjson.d.ts +0 -3
  568. package/dist/protocol/ndjson.d.ts.map +0 -1
  569. package/dist/protocol/ndjson.js +0 -20
  570. package/dist/protocol/ndjson.js.map +0 -1
  571. package/dist/protocol/sse.d.ts +0 -7
  572. package/dist/protocol/sse.d.ts.map +0 -1
  573. package/dist/protocol/sse.js +0 -25
  574. package/dist/protocol/sse.js.map +0 -1
  575. package/dist/proxy/pool.d.ts +0 -9
  576. package/dist/proxy/pool.d.ts.map +0 -1
  577. package/dist/proxy/pool.js +0 -27
  578. package/dist/proxy/pool.js.map +0 -1
  579. package/dist/queue/idempotency.d.ts +0 -10
  580. package/dist/queue/idempotency.d.ts.map +0 -1
  581. package/dist/queue/idempotency.js +0 -13
  582. package/dist/queue/idempotency.js.map +0 -1
  583. package/dist/queue/persistent.d.ts +0 -14
  584. package/dist/queue/persistent.d.ts.map +0 -1
  585. package/dist/queue/persistent.js +0 -66
  586. package/dist/queue/persistent.js.map +0 -1
  587. package/dist/queue/queue.d.ts +0 -7
  588. package/dist/queue/queue.d.ts.map +0 -1
  589. package/dist/queue/queue.js +0 -55
  590. package/dist/queue/queue.js.map +0 -1
  591. package/dist/queue/saga.d.ts +0 -5
  592. package/dist/queue/saga.d.ts.map +0 -1
  593. package/dist/queue/saga.js +0 -20
  594. package/dist/queue/saga.js.map +0 -1
  595. package/dist/release/assets.d.ts +0 -144
  596. package/dist/release/assets.d.ts.map +0 -1
  597. package/dist/release/assets.js +0 -157
  598. package/dist/release/assets.js.map +0 -1
  599. package/dist/release/evidence.d.ts +0 -92
  600. package/dist/release/evidence.d.ts.map +0 -1
  601. package/dist/release/evidence.js +0 -148
  602. package/dist/release/evidence.js.map +0 -1
  603. package/dist/release/verify.d.ts +0 -12
  604. package/dist/release/verify.d.ts.map +0 -1
  605. package/dist/release/verify.js +0 -112
  606. package/dist/release/verify.js.map +0 -1
  607. package/dist/runners/chain.d.ts +0 -125
  608. package/dist/runners/chain.d.ts.map +0 -1
  609. package/dist/runners/chain.js +0 -95
  610. package/dist/runners/chain.js.map +0 -1
  611. package/dist/runners/health.d.ts +0 -36
  612. package/dist/runners/health.d.ts.map +0 -1
  613. package/dist/runners/health.js +0 -26
  614. package/dist/runners/health.js.map +0 -1
  615. package/dist/runners/heartbeat.d.ts +0 -23
  616. package/dist/runners/heartbeat.d.ts.map +0 -1
  617. package/dist/runners/heartbeat.js +0 -29
  618. package/dist/runners/heartbeat.js.map +0 -1
  619. package/dist/runners/inprocess.d.ts +0 -17
  620. package/dist/runners/inprocess.d.ts.map +0 -1
  621. package/dist/runners/inprocess.js +0 -20
  622. package/dist/runners/inprocess.js.map +0 -1
  623. package/dist/runners/scheduler.d.ts +0 -5
  624. package/dist/runners/scheduler.d.ts.map +0 -1
  625. package/dist/runners/scheduler.js +0 -19
  626. package/dist/runners/scheduler.js.map +0 -1
  627. package/dist/runtime/abort.d.ts +0 -8
  628. package/dist/runtime/abort.d.ts.map +0 -1
  629. package/dist/runtime/abort.js +0 -13
  630. package/dist/runtime/abort.js.map +0 -1
  631. package/dist/runtime/compatibility.d.ts +0 -37
  632. package/dist/runtime/compatibility.d.ts.map +0 -1
  633. package/dist/runtime/compatibility.js +0 -10
  634. package/dist/runtime/compatibility.js.map +0 -1
  635. package/dist/runtime/detect.d.ts +0 -13
  636. package/dist/runtime/detect.d.ts.map +0 -1
  637. package/dist/runtime/detect.js +0 -18
  638. package/dist/runtime/detect.js.map +0 -1
  639. package/dist/runtime/engine.d.ts +0 -20
  640. package/dist/runtime/engine.d.ts.map +0 -1
  641. package/dist/runtime/engine.js +0 -61
  642. package/dist/runtime/engine.js.map +0 -1
  643. package/dist/runtime/retry.d.ts +0 -19
  644. package/dist/runtime/retry.d.ts.map +0 -1
  645. package/dist/runtime/retry.js +0 -54
  646. package/dist/runtime/retry.js.map +0 -1
  647. package/dist/runtime/worker.d.ts +0 -10
  648. package/dist/runtime/worker.d.ts.map +0 -1
  649. package/dist/runtime/worker.js +0 -25
  650. package/dist/runtime/worker.js.map +0 -1
  651. package/dist/scrape/cache.d.ts +0 -45
  652. package/dist/scrape/cache.d.ts.map +0 -1
  653. package/dist/scrape/cache.js +0 -45
  654. package/dist/scrape/cache.js.map +0 -1
  655. package/dist/scrape/crawl.d.ts +0 -47
  656. package/dist/scrape/crawl.d.ts.map +0 -1
  657. package/dist/scrape/crawl.js +0 -114
  658. package/dist/scrape/crawl.js.map +0 -1
  659. package/dist/scrape/extract.d.ts +0 -63
  660. package/dist/scrape/extract.d.ts.map +0 -1
  661. package/dist/scrape/extract.js +0 -47
  662. package/dist/scrape/extract.js.map +0 -1
  663. package/dist/scrape/normalize.d.ts +0 -52
  664. package/dist/scrape/normalize.d.ts.map +0 -1
  665. package/dist/scrape/normalize.js +0 -102
  666. package/dist/scrape/normalize.js.map +0 -1
  667. package/dist/scrape/robots.d.ts +0 -37
  668. package/dist/scrape/robots.d.ts.map +0 -1
  669. package/dist/scrape/robots.js +0 -71
  670. package/dist/scrape/robots.js.map +0 -1
  671. package/dist/scrape/schema.d.ts +0 -23
  672. package/dist/scrape/schema.d.ts.map +0 -1
  673. package/dist/scrape/schema.js +0 -92
  674. package/dist/scrape/schema.js.map +0 -1
  675. package/dist/scrape/scraper.d.ts +0 -6
  676. package/dist/scrape/scraper.d.ts.map +0 -1
  677. package/dist/scrape/scraper.js +0 -46
  678. package/dist/scrape/scraper.js.map +0 -1
  679. package/dist/scrape/semantic.d.ts +0 -25
  680. package/dist/scrape/semantic.d.ts.map +0 -1
  681. package/dist/scrape/semantic.js +0 -27
  682. package/dist/scrape/semantic.js.map +0 -1
  683. package/dist/server/node.d.ts +0 -7
  684. package/dist/server/node.d.ts.map +0 -1
  685. package/dist/server/node.js.map +0 -1
  686. package/dist/sessions/file.d.ts +0 -25
  687. package/dist/sessions/file.d.ts.map +0 -1
  688. package/dist/sessions/file.js +0 -13
  689. package/dist/sessions/file.js.map +0 -1
  690. package/dist/sessions/replay.d.ts +0 -9
  691. package/dist/sessions/replay.d.ts.map +0 -1
  692. package/dist/sessions/replay.js +0 -70
  693. package/dist/sessions/replay.js.map +0 -1
  694. package/dist/sessions/store.d.ts +0 -25
  695. package/dist/sessions/store.d.ts.map +0 -1
  696. package/dist/sessions/store.js +0 -13
  697. package/dist/sessions/store.js.map +0 -1
  698. package/dist/storage/adapter.d.ts +0 -5
  699. package/dist/storage/adapter.d.ts.map +0 -1
  700. package/dist/storage/adapter.js +0 -11
  701. package/dist/storage/adapter.js.map +0 -1
  702. package/dist/storage/cache.d.ts +0 -23
  703. package/dist/storage/cache.d.ts.map +0 -1
  704. package/dist/storage/cache.js +0 -79
  705. package/dist/storage/cache.js.map +0 -1
  706. package/dist/storage/checksum.d.ts +0 -3
  707. package/dist/storage/checksum.d.ts.map +0 -1
  708. package/dist/storage/checksum.js +0 -19
  709. package/dist/storage/checksum.js.map +0 -1
  710. package/dist/storage/chunked.d.ts +0 -21
  711. package/dist/storage/chunked.d.ts.map +0 -1
  712. package/dist/storage/chunked.js +0 -67
  713. package/dist/storage/chunked.js.map +0 -1
  714. package/dist/storage/content.d.ts +0 -24
  715. package/dist/storage/content.d.ts.map +0 -1
  716. package/dist/storage/content.js +0 -44
  717. package/dist/storage/content.js.map +0 -1
  718. package/dist/storage/filehosting.d.ts +0 -2
  719. package/dist/storage/filehosting.d.ts.map +0 -1
  720. package/dist/storage/filehosting.js +0 -24
  721. package/dist/storage/filehosting.js.map +0 -1
  722. package/dist/storage/githubcontents.d.ts +0 -2
  723. package/dist/storage/githubcontents.d.ts.map +0 -1
  724. package/dist/storage/githubcontents.js +0 -29
  725. package/dist/storage/githubcontents.js.map +0 -1
  726. package/dist/storage/index.d.ts +0 -12
  727. package/dist/storage/index.d.ts.map +0 -1
  728. package/dist/storage/index.js +0 -12
  729. package/dist/storage/index.js.map +0 -1
  730. package/dist/storage/local.d.ts +0 -2
  731. package/dist/storage/local.d.ts.map +0 -1
  732. package/dist/storage/local.js +0 -72
  733. package/dist/storage/local.js.map +0 -1
  734. package/dist/storage/memory.d.ts +0 -6
  735. package/dist/storage/memory.d.ts.map +0 -1
  736. package/dist/storage/memory.js +0 -36
  737. package/dist/storage/memory.js.map +0 -1
  738. package/dist/storage/pool.d.ts +0 -95
  739. package/dist/storage/pool.d.ts.map +0 -1
  740. package/dist/storage/pool.js +0 -202
  741. package/dist/storage/pool.js.map +0 -1
  742. package/dist/storage/s3compatible.d.ts +0 -3
  743. package/dist/storage/s3compatible.d.ts.map +0 -1
  744. package/dist/storage/s3compatible.js +0 -70
  745. package/dist/storage/s3compatible.js.map +0 -1
  746. package/dist/storage/sync.d.ts +0 -47
  747. package/dist/storage/sync.d.ts.map +0 -1
  748. package/dist/storage/sync.js +0 -75
  749. package/dist/storage/sync.js.map +0 -1
  750. package/dist/surfaces/adapters.d.ts +0 -97
  751. package/dist/surfaces/adapters.d.ts.map +0 -1
  752. package/dist/surfaces/adapters.js +0 -50
  753. package/dist/surfaces/adapters.js.map +0 -1
  754. package/dist/surfaces/controls.d.ts +0 -18
  755. package/dist/surfaces/controls.d.ts.map +0 -1
  756. package/dist/surfaces/controls.js +0 -45
  757. package/dist/surfaces/controls.js.map +0 -1
  758. package/dist/surfaces/manifest.d.ts +0 -68
  759. package/dist/surfaces/manifest.d.ts.map +0 -1
  760. package/dist/surfaces/manifest.js +0 -42
  761. package/dist/surfaces/manifest.js.map +0 -1
  762. package/dist/surfaces/n8n.d.ts +0 -25
  763. package/dist/surfaces/n8n.d.ts.map +0 -1
  764. package/dist/surfaces/n8n.js +0 -31
  765. package/dist/surfaces/n8n.js.map +0 -1
  766. package/dist/surfaces/operations.d.ts +0 -32
  767. package/dist/surfaces/operations.d.ts.map +0 -1
  768. package/dist/surfaces/operations.js +0 -53
  769. package/dist/surfaces/operations.js.map +0 -1
  770. package/dist/surfaces/requirements.d.ts +0 -29
  771. package/dist/surfaces/requirements.d.ts.map +0 -1
  772. package/dist/surfaces/requirements.js +0 -50
  773. package/dist/surfaces/requirements.js.map +0 -1
  774. package/dist/surfaces/targets.d.ts +0 -196
  775. package/dist/surfaces/targets.d.ts.map +0 -1
  776. package/dist/surfaces/targets.js +0 -27
  777. package/dist/surfaces/targets.js.map +0 -1
  778. package/dist/webhook/delivery.d.ts +0 -18
  779. package/dist/webhook/delivery.d.ts.map +0 -1
  780. package/dist/webhook/delivery.js +0 -36
  781. package/dist/webhook/delivery.js.map +0 -1
  782. package/dist/webhook/receiver.d.ts +0 -26
  783. package/dist/webhook/receiver.d.ts.map +0 -1
  784. package/dist/webhook/receiver.js +0 -24
  785. package/dist/webhook/receiver.js.map +0 -1
  786. package/dist/webhook/signature.d.ts +0 -3
  787. package/dist/webhook/signature.d.ts.map +0 -1
  788. package/dist/webhook/signature.js +0 -7
  789. package/dist/webhook/signature.js.map +0 -1
  790. package/dist/workflow/manifest.d.ts +0 -22
  791. package/dist/workflow/manifest.d.ts.map +0 -1
  792. package/dist/workflow/manifest.js +0 -21
  793. package/dist/workflow/manifest.js.map +0 -1
  794. package/dist/workflow/registry.d.ts +0 -7
  795. package/dist/workflow/registry.d.ts.map +0 -1
  796. package/dist/workflow/registry.js +0 -18
  797. package/dist/workflow/registry.js.map +0 -1
  798. package/dist/workflow/templates.d.ts +0 -6
  799. package/dist/workflow/templates.d.ts.map +0 -1
  800. package/dist/workflow/templates.js +0 -18
  801. package/dist/workflow/templates.js.map +0 -1
  802. package/dist/workflow/triggers.d.ts +0 -64
  803. package/dist/workflow/triggers.d.ts.map +0 -1
  804. package/dist/workflow/triggers.js +0 -99
  805. package/dist/workflow/triggers.js.map +0 -1
  806. package/docs/logs/.gitkeep +0 -0
  807. package/docs/plans/00.index.md +0 -50
  808. package/docs/plans/01.architecture.md +0 -86
  809. package/docs/plans/02.research.computer.use.md +0 -58
  810. package/docs/plans/03.research.captcha.bypass.md +0 -68
  811. package/docs/plans/04.research.sandbox.ai.md +0 -52
  812. package/docs/plans/05.capture.platform.md +0 -57
  813. package/docs/plans/06.dependencies.md +0 -97
  814. package/docs/plans/07.captcha.test.page.md +0 -41
  815. package/docs/plans/08.production.infra.md +0 -70
  816. package/docs/plans/09.database.schema.md +0 -121
  817. package/docs/plans/10.cloudinary.storage.md +0 -57
  818. package/docs/plans/11.movement.logs.json.md +0 -72
  819. package/docs/plans/12.research.atlas.agent.browser.md +0 -79
  820. package/docs/plans/13.research.anti.detection.md +0 -898
  821. package/docs/plans/14.research.proxy.md +0 -1495
  822. package/docs/plans/15.research.retry.rate.limit.md +0 -1958
  823. package/docs/plans/16.research.crawling.md +0 -1417
  824. package/docs/plans/17.research.caching.md +0 -1610
  825. package/docs/plans/18.research.content.extraction.md +0 -1952
  826. package/docs/plans/19.research.errors.events.md +0 -1523
  827. package/docs/plans/20.research.zod.validation.md +0 -1350
  828. package/docs/plans/21.research.batch.concurrency.md +0 -1888
  829. package/docs/plans/22.research.universal.runtime.md +0 -944
  830. package/docs/plans/23.research.ai.integration.md +0 -1465
  831. package/docs/plans/24.research.memory.persistence.md +0 -1979
  832. package/docs/plans/25.research.server.api.md +0 -342
  833. package/docs/plans/26.research.compilation.md +0 -249
  834. package/docs/plans/27.research.html.parsing.md +0 -251
  835. package/docs/plans/28.action.plan.md +0 -50
  836. package/docs/plans/29.api.reference.md +0 -174
  837. package/docs/plans/30.architecture.plan.md +0 -94
  838. package/docs/plans/31.auditoria.dados.md +0 -163
  839. package/docs/plans/32.bots.automacao.computacional.md +0 -214
  840. package/docs/plans/33.bots.codigo.revisao.md +0 -220
  841. package/docs/plans/34.bots.seguranca.cicd.md +0 -366
  842. package/docs/plans/35.comparativo.concorrencia.md +0 -464
  843. package/docs/plans/36.computational.memory.md +0 -340
  844. package/docs/plans/37.deploystrategy.md +0 -394
  845. package/docs/plans/38.flow.md +0 -155
  846. package/docs/plans/39.multi.platform.bot.md +0 -252
  847. package/docs/plans/40.npm.publish.md +0 -250
  848. package/docs/plans/41.o.que.falta.md +0 -407
  849. package/docs/plans/42.pesquisa.concorrencia.md +0 -721
  850. package/docs/plans/43.plan.universal.architecture.md +0 -496
  851. package/docs/plans/44.reference.md +0 -100
  852. package/docs/plans/45.robotarchitecture.md +0 -237
  853. package/docs/plans/46.scdnintegration.md +0 -284
  854. package/docs/plans/47.multiforge.readme.md +0 -129
  855. package/docs/plans/48.theory.v4.repo.os.md +0 -152
  856. package/docs/plans/49.third.party.infra.md +0 -12
  857. package/docs/plans/50.file.as.compute.md +0 -39
  858. package/docs/plans/51.architecture.virtual.processor.md +0 -80
  859. package/docs/plans/52.manifesto.v8.md +0 -11
  860. package/docs/plans/58.cdn.list.md +0 -23
  861. package/docs/plans/59.sql.frameworks.md +0 -33
  862. package/docs/plans/60.sql.thirdparty.md +0 -26
  863. package/docs/plans/61.objective.multiforge.md +0 -63
  864. package/docs/plans/62.huggingface.upload.md +0 -26
  865. package/docs/plans/63.kaggle.upload.md +0 -24
  866. package/docs/plans/64.npm.storage.md +0 -30
  867. package/docs/plans/65.rclone.terabox.md +0 -32
  868. package/docs/plans/66.buckets.and.models.todo.md +0 -14
  869. package/docs/plans/67.database.todo.md +0 -13
  870. package/docs/plans/68.deploy.packages.todo.md +0 -12
  871. package/docs/plans/69.report.human.operator.md +0 -133
  872. package/docs/plans/70.report.brain2qwerty.ems.md +0 -135
  873. package/docs/plans/71.report.hd.infinito.vram.md +0 -155
  874. package/docs/plans/72.plan.hd.infinito.node.md +0 -146
  875. package/docs/plans/73.plan.scifi.repos.md +0 -125
  876. package/docs/plans/74.000.manifesto.v8.flat.2..md +0 -11
  877. package/docs/plans/README.md +0 -489
  878. package/docs/plans/aggregate_platforms.mjs +0 -146
  879. package/docs/plans/examplesession.json +0 -36
  880. package/docs/plans/missing-facts.md +0 -192
  881. package/docs/plans/models.md +0 -64
  882. package/docs/plans/organize.cjs +0 -270
  883. package/docs/plans/platforms.md +0 -2887
  884. package/docs/plans/sites.md +0 -31322
  885. package/docs/sources/farm.py +0 -117
  886. package/docs/sources/html/saddle1.html +0 -132
  887. package/docs/sources/html/saddle2.html +0 -157
  888. package/docs/sources/html/saddle3.html +0 -119
  889. package/docs/sources/html/saddle4.html +0 -144
  890. package/docs/sources/html/saddle5.html +0 -72
  891. package/docs/sources/html/saddle6.html +0 -171
  892. package/docs/sources/html/saddle7.html +0 -236
  893. package/docs/sources/saddle.ts +0 -74
  894. package/docs/sources/schema.prisma +0 -88
  895. package/docs/sources/script.sh +0 -64
  896. package/docs/sources/workflows.yml +0 -458
  897. package/docs/talks1/_body.txt +0 -14
  898. package/docs/talks1/_index.md +0 -15
  899. package/docs/talks1/_screenshot.png +0 -0
  900. package/docs/talks1/assistant-01.md +0 -5
  901. package/docs/talks1/assistant-02.md +0 -5
  902. package/docs/talks1/assistant-03.md +0 -531
  903. package/docs/talks1/assistant-04.md +0 -26
  904. package/docs/talks1/assistant-05.md +0 -774
  905. package/docs/talks1/assistant-06.md +0 -1718
  906. package/docs/talks1/scrape-share.cjs +0 -185
  907. package/docs/talks1/scrape-share.ts +0 -183
  908. package/docs/talks1/user-01.md +0 -3
  909. package/docs/talks1/user-02.md +0 -3
  910. package/docs/talks1/user-03.md +0 -88
  911. package/docs/talks1/user-04.md +0 -3
  912. package/docs/talks1/user-05.md +0 -3
  913. package/docs/talks1/user-06.md +0 -88
  914. package/docs/talks1/user-07.md +0 -88
  915. package/docs/talks2/_body.txt +0 -14
  916. package/docs/talks2/_index.md +0 -16
  917. package/docs/talks2/_screenshot.png +0 -0
  918. package/docs/talks2/assistant-01.md +0 -5
  919. package/docs/talks2/assistant-02.md +0 -5
  920. package/docs/talks2/assistant-03.md +0 -424
  921. package/docs/talks2/assistant-04.md +0 -598
  922. package/docs/talks2/assistant-05.md +0 -1280
  923. package/docs/talks2/assistant-06.md +0 -1227
  924. package/docs/talks2/assistant-07.md +0 -1252
  925. package/docs/talks2/user-01.md +0 -3
  926. package/docs/talks2/user-02.md +0 -3
  927. package/docs/talks2/user-03.md +0 -88
  928. package/docs/talks2/user-04.md +0 -88
  929. package/docs/talks2/user-05.md +0 -88
  930. package/docs/talks2/user-06.md +0 -88
  931. package/docs/talks2/user-07.md +0 -3
  932. package/docs/talks3/_body.txt +0 -467
  933. package/docs/talks3/_index.md +0 -10
  934. package/docs/talks3/_screenshot.png +0 -0
  935. package/docs/talks3/assistant-01.md +0 -417
  936. package/docs/talks3/assistant-02.md +0 -417
  937. package/docs/talks3/assistant-03.md +0 -29
  938. package/docs/talks3/assistant-04.md +0 -727
  939. package/docs/talks3/user-01.md +0 -88
  940. package/docs/talks3/user-02.md +0 -88
  941. package/docs/talks3/user-03.md +0 -3
  942. package/docs/talks3/user-04.md +0 -3
  943. package/docs/talks4/_body.txt +0 -14
  944. package/docs/talks4/_index.md +0 -12
  945. package/docs/talks4/_screenshot.png +0 -0
  946. package/docs/talks4/assistant-01.md +0 -5
  947. package/docs/talks4/assistant-02.md +0 -5
  948. package/docs/talks4/assistant-03.md +0 -35
  949. package/docs/talks4/assistant-04.md +0 -512
  950. package/docs/talks4/assistant-05.md +0 -599
  951. package/docs/talks4/user-01.md +0 -3
  952. package/docs/talks4/user-02.md +0 -3
  953. package/docs/talks4/user-03.md +0 -88
  954. package/docs/talks4/user-04.md +0 -88
  955. package/docs/talks4/user-05.md +0 -7
  956. package/docs/talks5/_body.txt +0 -14
  957. package/docs/talks5/_index.md +0 -13
  958. package/docs/talks5/_screenshot.png +0 -0
  959. package/docs/talks5/assistant-01.md +0 -5
  960. package/docs/talks5/assistant-02.md +0 -5
  961. package/docs/talks5/assistant-03.md +0 -690
  962. package/docs/talks5/assistant-04.md +0 -758
  963. package/docs/talks5/assistant-05.md +0 -974
  964. package/docs/talks5/user-01.md +0 -3
  965. package/docs/talks5/user-02.md +0 -3
  966. package/docs/talks5/user-03.md +0 -105
  967. package/docs/talks5/user-04.md +0 -105
  968. package/docs/talks5/user-05.md +0 -63
  969. package/docs/talks5/user-06.md +0 -105
  970. package/docs/talks6/_body.txt +0 -14
  971. package/docs/talks6/_index.md +0 -9
  972. package/docs/talks6/_screenshot.png +0 -0
  973. package/docs/talks6/assistant-01.md +0 -5
  974. package/docs/talks6/assistant-02.md +0 -5
  975. package/docs/talks6/assistant-03.md +0 -1499
  976. package/docs/talks6/user-01.md +0 -3
  977. package/docs/talks6/user-02.md +0 -3
  978. package/docs/talks6/user-03.md +0 -88
  979. package/docs/talks6/user-04.md +0 -88
  980. package/docs/talks7/_body.txt +0 -14
  981. package/docs/talks7/_index.md +0 -10
  982. package/docs/talks7/_screenshot.png +0 -0
  983. package/docs/talks7/assistant-01.md +0 -5
  984. package/docs/talks7/assistant-02.md +0 -5
  985. package/docs/talks7/assistant-03.md +0 -523
  986. package/docs/talks7/assistant-04.md +0 -617
  987. package/docs/talks7/user-01.md +0 -3
  988. package/docs/talks7/user-02.md +0 -3
  989. package/docs/talks7/user-03.md +0 -105
  990. package/docs/talks7/user-04.md +0 -67
  991. package/docs/talks8/conversa1.txt +0 -1322
  992. package/docs/talks8/conversa2.txt +0 -237
  993. package/docs/talks9/Beyond the Obvious_ 50 Plataformas Auto-Hospedadas de Forja de C/303/263digo para Al/303/251m de Gitea e GitLab.md" +0 -174
  994. package/docs/talks9/De NPM a Multi-Linguagem_ Uma Arquitetura T/303/251cnica para a Execu/303/247/303/243o Integrada de C/303/263digo no Ecossistema Node.js.md" +0 -59
  995. package/docs/talks9/De NPM a VMs Virtuais_ Uma An/303/241lise Arquitet/303/264nica para a Realiza/303/247/303/243o do Ciclo de Vida do Projeto SADDLE.md" +0 -91
  996. package/docs/talks9/Mapeamento da Engrenagem Computacional_ Uma Arquitetura para Execu/303/247/303/243o Isolada e Persist/303/252ncia em Ambientes Distribu/303/255dos.md" +0 -116
  997. package/docs/talks9/O Cen/303/241rio Pr/303/241tico do SADDLE_ Uma An/303/241lise de Viabilidade e Modelo de Ciclo de Vida Integrado.md" +0 -128
  998. package/docs/talks9/README (2).md +0 -489
  999. package/docs/talks9/README.md +0 -198
  1000. package/docs/talks9/Viabilidade do Saddle_ Uma An/303/241lise T/303/251cnica da Transforma/303/247/303/243o de Armazenamento Remoto em Mem/303/263ria Computacional.md" +0 -80
  1001. package/docs/talks9/conversa.txt +0 -544
  1002. package/docs/talks9/other (2).md +0 -39
  1003. package/docs/talks9/other.md +0 -57
  1004. package/docs/talks9/outro.txt +0 -24
  1005. /package/{extension/README.md → docs/extension.md} +0 -0
@@ -1,1958 +0,0 @@
1
- # Pesquisa: Retry, Backoff e Rate Limiting (2026)
2
-
3
- ## Sumário
4
-
5
- 1. [Pacotes de Retry](#1-pacotes-de-retry)
6
- 2. [Comparação p-retry vs async-retry](#2-comparação-p-retry-vs-async-retry)
7
- 3. [Algoritmos de Rate Limiting](#3-algoritmos-de-rate-limiting)
8
- 4. [Pacotes de Rate Limiting](#4-pacotes-de-rate-limiting)
9
- 5. [Rate Limiting por Domínio](#5-rate-limiting-por-dominio)
10
- 6. [Status Codes para Retry](#6-status-para-retry)
11
- 7. [Respeitando Retry-After](#7-respeitando-retry-after)
12
- 8. [Retry com Proxy Rotation](#8-retry-com-proxy-rotation)
13
- 9. [Exemplos Completos](#9-exemplos-completos)
14
-
15
- ---
16
-
17
- ## 1. Pacotes de Retry
18
-
19
- ### 1.1 p-retry (Recomendado)
20
-
21
- **Versão:** 8.0.0
22
- **Descrição:** Retry com suporte a AbortError e callbacks
23
- **Última atualização:** 2024
24
-
25
- ```javascript
26
- import pRetry from 'p-retry';
27
-
28
- // Uso básico
29
- const result = await pRetry(async () => {
30
- const response = await fetch('https://example.com');
31
- if (!response.ok) {
32
- throw new Error(`HTTP ${response.status}`);
33
- }
34
- return response.json();
35
- }, {
36
- retries: 3,
37
- factor: 2,
38
- minTimeout: 1000,
39
- maxTimeout: 10000,
40
- randomize: true,
41
- });
42
-
43
- // Com AbortController
44
- const controller = new AbortController();
45
- setTimeout(() => controller.abort(), 5000);
46
-
47
- const result = await pRetry(async (attemptNumber) => {
48
- console.log(`Attempt ${attemptNumber}`);
49
-
50
- const response = await fetch('https://example.com', {
51
- signal: controller.signal,
52
- });
53
-
54
- if (!response.ok) {
55
- throw new pRetry.AbortError(new Error(`Abort on ${response.status}`));
56
- }
57
-
58
- return response.json();
59
- }, {
60
- retries: 5,
61
- onFailedAttempt: async (error) => {
62
- console.log(`Attempt ${error.attemptNumber} failed`);
63
- console.log(`Failures: ${error.retriesLeft}`);
64
-
65
- // Abort em caso de erro 401/403
66
- if (error.message.includes('401') || error.message.includes('403')) {
67
- throw new pRetry.AbortError(error);
68
- }
69
- },
70
- });
71
- ```
72
-
73
- **Configuração avançada:**
74
- ```javascript
75
- import pRetry from 'p-retry';
76
-
77
- const result = await pRetry(async () => {
78
- // Lógica de retry
79
- }, {
80
- retries: 5, // Número máximo de retries
81
- factor: 2, // Fator de backoff exponencial
82
- minTimeout: 1000, // Timeout mínimo (1s)
83
- maxTimeout: 60000, // Timeout máximo (60s)
84
- randomize: true, // Adicionar aleatoriedade
85
- signal: controller.signal, // AbortSignal
86
- onFailedAttempt: async (error) => {
87
- // Callback após cada falha
88
- console.log(`Attempt ${error.attemptNumber} failed`);
89
- console.log(`Retries left: ${error.retriesLeft}`);
90
- },
91
- });
92
- ```
93
-
94
- ### 1.2 async-retry
95
-
96
- **Versão:** 1.3.3
97
- **Descrição:** Retry com suporte a bail function
98
- **Última atualização:** 2023
99
-
100
- ```javascript
101
- import retry from 'async-retry';
102
-
103
- // Uso básico
104
- const result = await retry(async (bail) => {
105
- const response = await fetch('https://example.com');
106
-
107
- // Bail em caso de erro 401
108
- if (response.status === 401) {
109
- bail(new Error('Unauthorized'));
110
- return;
111
- }
112
-
113
- if (!response.ok) {
114
- throw new Error(`HTTP ${response.status}`);
115
- }
116
-
117
- return response.json();
118
- }, {
119
- retries: 3,
120
- factor: 2,
121
- minTimeout: 1000,
122
- maxTimeout: 10000,
123
- randomize: true,
124
- });
125
-
126
- // Com retry callback
127
- const result = await retry(async (bail) => {
128
- // Lógica de retry
129
- }, {
130
- retries: 5,
131
- onRetry: (error, attempt) => {
132
- console.log(`Attempt ${attempt} failed, retrying...`);
133
- },
134
- });
135
- ```
136
-
137
- **Configuração avançada:**
138
- ```javascript
139
- import retry from 'async-retry';
140
-
141
- const result = await retry(async (bail) => {
142
- // Lógica de retry
143
- }, {
144
- retries: 5, // Número máximo de retries
145
- factor: 2, // Fator de backoff exponencial
146
- minTimeout: 1000, // Timeout mínimo (1s)
147
- maxTimeout: 60000, // Timeout máximo (60s)
148
- randomize: true, // Adicionar aleatoriedade
149
- bail: (error) => {
150
- // Função para parar retries
151
- return error.message.includes('401');
152
- },
153
- onRetry: (error, attempt) => {
154
- // Callback após cada falha
155
- console.log(`Attempt ${attempt} failed`);
156
- },
157
- });
158
- ```
159
-
160
- ### 1.3 retry
161
-
162
- **Versão:** 0.13.1
163
- **Descrição:** Biblioteca fundacional de retry
164
- **Última atualização:** 2022
165
-
166
- ```javascript
167
- import retry from 'retry';
168
-
169
- // Uso com callbacks
170
- const operation = retry.operation({
171
- retries: 5,
172
- factor: 2,
173
- minTimeout: 1000,
174
- maxTimeout: 60000,
175
- randomize: true,
176
- });
177
-
178
- operation.attempt(async (currentAttempt) => {
179
- try {
180
- const response = await fetch('https://example.com');
181
- if (!response.ok) {
182
- throw new Error(`HTTP ${response.status}`);
183
- }
184
- const data = await response.json();
185
- operation.stop();
186
- return data;
187
- } catch (error) {
188
- if (operation.retry(error)) {
189
- console.log(`Attempt ${currentAttempt} failed, retrying...`);
190
- } else {
191
- console.log(`All retries exhausted`);
192
- throw error;
193
- }
194
- }
195
- });
196
-
197
- // Uso com Promises
198
- import { promisify } from 'util';
199
- const retryAsync = promisify(retry);
200
-
201
- const result = await retryAsync(async () => {
202
- const response = await fetch('https://example.com');
203
- return response.json();
204
- }, {
205
- retries: 5,
206
- factor: 2,
207
- minTimeout: 1000,
208
- maxTimeout: 60000,
209
- });
210
- ```
211
-
212
- ### 1.4 exponential-backoff
213
-
214
- **Versão:** 3.1.3
215
- **Descrição:** Geração de delays com backoff exponencial
216
- **Última atualização:** 2023
217
-
218
- ```javascript
219
- import { ExponentialBackoff } from 'exponential-backoff';
220
-
221
- // Uso básico
222
- const backoff = new ExponentialBackoff({
223
- maxRetries: 5,
224
- initialDelay: 1000,
225
- maxDelay: 60000,
226
- factor: 2,
227
- jitter: true,
228
- });
229
-
230
- const result = await backoff.execute(async () => {
231
- const response = await fetch('https://example.com');
232
- if (!response.ok) {
233
- throw new Error(`HTTP ${response.status}`);
234
- }
235
- return response.json();
236
- });
237
-
238
- // Uso com delay manual
239
- import { getDelay } from 'exponential-backoff';
240
-
241
- for (let i = 0; i < 5; i++) {
242
- const delay = getDelay(i, {
243
- initialDelay: 1000,
244
- maxDelay: 60000,
245
- factor: 2,
246
- jitter: true,
247
- });
248
-
249
- console.log(`Attempt ${i + 1} will wait ${delay}ms`);
250
- }
251
- ```
252
-
253
- ---
254
-
255
- ## 2. Comparação p-retry vs async-retry
256
-
257
- ### Tabela Comparativa
258
-
259
- | Característica | p-retry 8.0.0 | async-retry 1.3.3 |
260
- |----------------|---------------|-------------------|
261
- | **Tipo** | ESM/CommonJS | CommonJS |
262
- | **AbortError** | Nativo | Via bail |
263
- | **Callbacks** | onFailedAttempt | onRetry |
264
- | **Bail** | AbortError | bail function |
265
- | **Signal** | AbortSignal | Não suporta |
266
- | **Fator de backoff** | Configurável | Configurável |
267
- | **Jitter** | Configurável | Configurável |
268
- | **Última atualização** | 2024 | 2023 |
269
- | **Manutenção** | Ativa | Estável |
270
- | **Bundle size** | ~2KB | ~1.5KB |
271
-
272
- ### Quando Usar Cada Um
273
-
274
- **Use p-retry quando:**
275
- - Precisa de AbortController/AbortSignal
276
- - Quer callbacks detalhados (onFailedAttempt)
277
- - Usa ESM nativo
278
- - Precisa de granularidade no controle de retry
279
-
280
- **Use async-retry quando:**
281
- - Prefere API com bail function
282
- - Usa CommonJS
283
- - Projeto já usa async-retry
284
- - Não precisa de AbortSignal
285
-
286
- ### Exemplo Comparativo
287
-
288
- ```javascript
289
- // p-retry
290
- import pRetry from 'p-retry';
291
-
292
- const result1 = await pRetry(async (attempt) => {
293
- const response = await fetch('https://example.com');
294
- if (response.status === 429) {
295
- throw new Error('Rate limited');
296
- }
297
- return response.json();
298
- }, {
299
- retries: 3,
300
- onFailedAttempt: async (error) => {
301
- console.log(`Attempt ${error.attemptNumber} failed`);
302
- },
303
- });
304
-
305
- // async-retry
306
- import retry from 'async-retry';
307
-
308
- const result2 = await retry(async (bail) => {
309
- const response = await fetch('https://example.com');
310
- if (response.status === 429) {
311
- bail(new Error('Rate limited'));
312
- return;
313
- }
314
- return response.json();
315
- }, {
316
- retries: 3,
317
- onRetry: (error, attempt) => {
318
- console.log(`Attempt ${attempt} failed`);
319
- },
320
- });
321
- ```
322
-
323
- ---
324
-
325
- ## 3. Algoritmos de Rate Limiting
326
-
327
- ### 3.1 Token Bucket
328
-
329
- **Como funciona:**
330
- - Bucket contém N tokens
331
- - Cada request consome 1 token
332
- - Tokens são adicionados a uma taxa fixa
333
- - Se bucket vazio, request é rejeitado
334
-
335
- **Vantagens:**
336
- - Permite bursts curtos
337
- - Simples de implementar
338
- - Baixa memória
339
-
340
- **Desvantagens:**
341
- - Não garante taxa suave
342
- - Burst pode sobrecarregar sistema
343
-
344
- ```javascript
345
- class TokenBucket {
346
- constructor(capacity, refillRate) {
347
- this.capacity = capacity;
348
- this.tokens = capacity;
349
- this.refillRate = refillRate; // tokens por segundo
350
- this.lastRefill = Date.now();
351
- }
352
-
353
- consume() {
354
- this.refill();
355
- if (this.tokens > 0) {
356
- this.tokens--;
357
- return true;
358
- }
359
- return false;
360
- }
361
-
362
- refill() {
363
- const now = Date.now();
364
- const elapsed = (now - this.lastRefill) / 1000;
365
- const tokensToAdd = elapsed * this.refillRate;
366
- this.tokens = Math.min(this.capacity, this.tokens + tokensToAdd);
367
- this.lastRefill = now;
368
- }
369
-
370
- getTokens() {
371
- this.refill();
372
- return Math.floor(this.tokens);
373
- }
374
- }
375
-
376
- // Uso
377
- const bucket = new TokenBucket(10, 1); // 10 tokens, 1 por segundo
378
-
379
- async function makeRequest() {
380
- if (bucket.consume()) {
381
- return await fetch('https://example.com');
382
- } else {
383
- throw new Error('Rate limited');
384
- }
385
- }
386
- ```
387
-
388
- ### 3.2 Sliding Window Log
389
-
390
- **Como funciona:**
391
- - Mantém log de todos os requests no último período
392
- - Conta requests no período atual
393
- - Se count > limit, rejeita
394
-
395
- **Vantagens:**
396
- - Preciso
397
- - Sem edge cases
398
-
399
- **Desvantagens:**
400
- - Alta memória (armazena todos os timestamps)
401
- - Computacionalmente caro
402
-
403
- ```javascript
404
- class SlidingWindowLog {
405
- constructor(windowSize, maxRequests) {
406
- this.windowSize = windowSize; // em ms
407
- this.maxRequests = maxRequests;
408
- this.logs = [];
409
- }
410
-
411
- isAllowed() {
412
- const now = Date.now();
413
- const windowStart = now - this.windowSize;
414
-
415
- // Remover logs antigos
416
- this.logs = this.logs.filter(time => time > windowStart);
417
-
418
- if (this.logs.length < this.maxRequests) {
419
- this.logs.push(now);
420
- return true;
421
- }
422
-
423
- return false;
424
- }
425
-
426
- getCount() {
427
- const now = Date.now();
428
- const windowStart = now - this.windowSize;
429
- return this.logs.filter(time => time > windowStart).length;
430
- }
431
- }
432
-
433
- // Uso
434
- const limiter = new SlidingWindowLog(60000, 100); // 100 requests por minuto
435
-
436
- async function makeRequest() {
437
- if (limiter.isAllowed()) {
438
- return await fetch('https://example.com');
439
- } else {
440
- throw new Error('Rate limited');
441
- }
442
- }
443
- ```
444
-
445
- ### 3.3 Sliding Window Counter
446
-
447
- **Como funciona:**
448
- - Divide tempo em janelas fixas
449
- - Conta requests em cada janela
450
- - Estima contagem atual baseado na janela anterior
451
-
452
- **Vantagens:**
453
- - Balance entre precisão e performance
454
- - Baixa memória
455
- - Simples
456
-
457
- **Desvantagens:**
458
- - Não é 100% preciso
459
- - Pode ter edge cases
460
-
461
- ```javascript
462
- class SlidingWindowCounter {
463
- constructor(windowSize, maxRequests) {
464
- this.windowSize = windowSize;
465
- this.maxRequests = maxRequests;
466
- this.currentWindow = Math.floor(Date.now() / windowSize);
467
- this.currentCount = 0;
468
- this.previousCount = 0;
469
- }
470
-
471
- isAllowed() {
472
- const now = Date.now();
473
- const currentWindow = Math.floor(now / this.windowSize);
474
-
475
- // Nova janela
476
- if (currentWindow !== this.currentWindow) {
477
- this.previousCount = this.currentCount;
478
- this.currentCount = 0;
479
- this.currentWindow = currentWindow;
480
- }
481
-
482
- // Calcular contagem estimada
483
- const elapsed = now % this.windowSize;
484
- const weight = elapsed / this.windowSize;
485
- const estimatedCount = this.previousCount * (1 - weight) + this.currentCount;
486
-
487
- if (estimatedCount < this.maxRequests) {
488
- this.currentCount++;
489
- return true;
490
- }
491
-
492
- return false;
493
- }
494
-
495
- getCount() {
496
- const now = Date.now();
497
- const currentWindow = Math.floor(now / this.windowSize);
498
-
499
- if (currentWindow !== this.currentWindow) {
500
- return 0;
501
- }
502
-
503
- return this.currentCount;
504
- }
505
- }
506
-
507
- // Uso
508
- const limiter = new SlidingWindowCounter(60000, 100); // 100 requests por minuto
509
-
510
- async function makeRequest() {
511
- if (limiter.isAllowed()) {
512
- return await fetch('https://example.com');
513
- } else {
514
- throw new Error('Rate limited');
515
- }
516
- }
517
- ```
518
-
519
- ### 3.4 Fixed Window
520
-
521
- **Como funciona:**
522
- - Divide tempo em janelas fixas
523
- - Conta requests em cada janela
524
- - Reseta contador no início da janela
525
-
526
- **Vantagens:**
527
- - Simples
528
- - Baixa memória
529
- - Rápido
530
-
531
- **Desvantagens:**
532
- - Edge cases no início/fim da janela
533
- - Pode permitir bursts
534
-
535
- ```javascript
536
- class FixedWindow {
537
- constructor(windowSize, maxRequests) {
538
- this.windowSize = windowSize;
539
- this.maxRequests = maxRequests;
540
- this.windowStart = Date.now();
541
- this.count = 0;
542
- }
543
-
544
- isAllowed() {
545
- const now = Date.now();
546
-
547
- // Nova janela
548
- if (now - this.windowStart >= this.windowSize) {
549
- this.windowStart = now;
550
- this.count = 0;
551
- }
552
-
553
- if (this.count < this.maxRequests) {
554
- this.count++;
555
- return true;
556
- }
557
-
558
- return false;
559
- }
560
-
561
- getCount() {
562
- const now = Date.now();
563
- if (now - this.windowStart >= this.windowSize) {
564
- return 0;
565
- }
566
- return this.count;
567
- }
568
- }
569
-
570
- // Uso
571
- const limiter = new FixedWindow(60000, 100); // 100 requests por minuto
572
-
573
- async function makeRequest() {
574
- if (limiter.isAllowed()) {
575
- return await fetch('https://example.com');
576
- } else {
577
- throw new Error('Rate limited');
578
- }
579
- }
580
- ```
581
-
582
- ### 3.5 Leaky Bucket
583
-
584
- **Como funciona:**
585
- - Requests entram em uma fila
586
- - Requests saem a uma taxa fixa
587
- - Se fila cheia, request é rejeitado
588
-
589
- **Vantagens:**
590
- - Taxa suave e constante
591
- - Sem bursts
592
-
593
- **Desvantagens:**
594
- - Alta latência
595
- - Não permite bursts
596
- - Complexidade
597
-
598
- ```javascript
599
- class LeakyBucket {
600
- constructor(capacity, leakRate) {
601
- this.capacity = capacity;
602
- this.leakRate = leakRate; // requests por segundo
603
- this.queue = [];
604
- this.lastLeak = Date.now();
605
- }
606
-
607
- isAllowed() {
608
- this.leak();
609
-
610
- if (this.queue.length < this.capacity) {
611
- this.queue.push(Date.now());
612
- return true;
613
- }
614
-
615
- return false;
616
- }
617
-
618
- leak() {
619
- const now = Date.now();
620
- const elapsed = (now - this.lastLeak) / 1000;
621
- const leakCount = Math.floor(elapsed * this.leakRate);
622
-
623
- if (leakCount > 0) {
624
- this.queue.splice(0, leakCount);
625
- this.lastLeak = now;
626
- }
627
- }
628
-
629
- getQueueSize() {
630
- this.leak();
631
- return this.queue.length;
632
- }
633
- }
634
-
635
- // Uso
636
- const bucket = new LeakyBucket(10, 1); // 10 capacity, 1 por segundo
637
-
638
- async function makeRequest() {
639
- if (bucket.isAllowed()) {
640
- return await fetch('https://example.com');
641
- } else {
642
- throw new Error('Rate limited');
643
- }
644
- }
645
- ```
646
-
647
- ### Tabela Comparativa de Algoritmos
648
-
649
- | Algoritmo | Precisão | Performance | Memória | Burst | Complexidade |
650
- |-----------|----------|-------------|---------|-------|--------------|
651
- | Token Bucket | Média | Alta | Baixa | Sim | Baixa |
652
- | Sliding Window Log | Alta | Baixa | Alta | Não | Média |
653
- | Sliding Window Counter | Média-Alta | Alta | Baixa | Parcial | Média |
654
- | Fixed Window | Baixa | Alta | Baixa | Sim | Baixa |
655
- | Leaky Bucket | Alta | Média | Média | Não | Média |
656
-
657
- ---
658
-
659
- ## 4. Pacotes de Rate Limiting
660
-
661
- ### 4.1 bottleneck
662
-
663
- **Versão:** 2.19.5
664
- **Descrição:** Rate limiting avançado com clusters e jobs
665
- **Última atualização:** 2023
666
-
667
- ```javascript
668
- import Bottleneck from 'bottleneck';
669
-
670
- // Rate limiter básico
671
- const limiter = new Bottleneck({
672
- minTime: 100, // Mínimo 100ms entre requests
673
- maxConcurrent: 5, // Máximo 5 requests simultâneos
674
- reservoir: 10, // 10 requests por período
675
- reservoirRefreshAmount: 10,
676
- reservoirRefreshInterval: 60000, // 1 minuto
677
- });
678
-
679
- // Usar com fetch
680
- async function makeRequest(url) {
681
- return limiter.schedule(async () => {
682
- const response = await fetch(url);
683
- return response.json();
684
- });
685
- }
686
-
687
- // Múltiplos limiters (clusters)
688
- const cluster = new Bottleneck.Cluster({
689
- datastore: 'redis',
690
- redis: { host: 'localhost', port: 6379 },
691
- });
692
-
693
- const limiter1 = cluster.cluster('api1');
694
- const limiter2 = cluster.cluster('api2');
695
-
696
- // Rate limits diferentes por endpoint
697
- const apiLimiter = new Bottleneck({
698
- reservoir: 100,
699
- reservoirRefreshAmount: 100,
700
- reservoirRefreshInterval: 60000,
701
- });
702
-
703
- const searchLimiter = new Bottleneck({
704
- minTime: 500,
705
- maxConcurrent: 2,
706
- });
707
-
708
- // Encadear limiters
709
- const combinedLimiter = Bottleneck.chain(apiLimiter, searchLimiter);
710
- ```
711
-
712
- ### 4.2 p-throttle
713
-
714
- **Versão:** 6.2.0
715
- **Descrição:** Throttling de funções com suporte a ESM
716
- **Última atualização:** 2023
717
-
718
- ```javascript
719
- import pThrottle from 'p-throttle';
720
-
721
- // Limitar a 10 chamadas por segundo
722
- const throttle = pThrottle({
723
- limit: 10,
724
- interval: 1000,
725
- strict: true,
726
- });
727
-
728
- const throttledFetch = throttle(async (url) => {
729
- const response = await fetch(url);
730
- return response.json();
731
- });
732
-
733
- // Usar
734
- for (const url of urls) {
735
- const data = await throttledFetch(url);
736
- console.log(data);
737
- }
738
-
739
- // Throttled function com abort
740
- const controller = new AbortController();
741
- const throttledFetchWithAbort = throttle(async (url) => {
742
- const response = await fetch(url, { signal: controller.signal });
743
- return response.json();
744
- });
745
- ```
746
-
747
- ### 4.3 p-limit
748
-
749
- **Versão:** 7.3.0
750
- **Descrição:** Limitação de concorrência
751
- **Última atualização:** 2023
752
-
753
- ```javascript
754
- import pLimit from 'p-limit';
755
-
756
- // Limitar a 5 concorrências
757
- const limit = pLimit(5);
758
-
759
- // Criar tasks com limite
760
- const tasks = urls.map(url => {
761
- return limit(async () => {
762
- const response = await fetch(url);
763
- return response.json();
764
- });
765
- });
766
-
767
- const results = await Promise.all(tasks);
768
-
769
- // Verificar estado
770
- console.log(limit.activeCount); // Requests ativos
771
- console.log(limit.pendingCount); // Requests pendentes
772
-
773
- // Limitar por domínio
774
- const domainLimits = new Map();
775
-
776
- function getLimiterForDomain(domain) {
777
- if (!domainLimits.has(domain)) {
778
- domainLimits.set(domain, pLimit(5));
779
- }
780
- return domainLimits.get(domain);
781
- }
782
-
783
- // Usar
784
- const limiter = getLimiterForDomain('example.com');
785
- const result = await limiter(async () => {
786
- return await fetch('https://example.com/api');
787
- });
788
- ```
789
-
790
- ### 4.4 p-queue
791
-
792
- **Versão:** 9.2.0
793
- **Descrição:** Fila de tarefas com prioridade
794
- **Última atualização:** 2024
795
-
796
- ```javascript
797
- import PQueue from 'p-queue';
798
-
799
- // Fila com limite de concorrência
800
- const queue = new PQueue({
801
- concurrency: 5,
802
- intervalCap: 10,
803
- interval: 1000,
804
- });
805
-
806
- // Adicionar tarefas com prioridade
807
- queue.add(async () => {
808
- return await fetch('https://example.com/low');
809
- }, { priority: 1 });
810
-
811
- queue.add(async () => {
812
- return await fetch('https://example.com/high');
813
- }, { priority: 10 });
814
-
815
- // Verificar estado
816
- console.log(queue.size); // Tamanho da fila
817
- console.log(queue.pending); // Tarefas pendentes
818
- console.log(queue.isPaused); // Se está pausada
819
-
820
- // Pausar/Retomar
821
- queue.pause();
822
- queue.start();
823
-
824
- // Adicionar com timeout
825
- queue.add(async () => {
826
- return await fetch('https://example.com');
827
- }, {
828
- timeout: 5000,
829
- signal: AbortSignal.timeout(5000),
830
- });
831
- ```
832
-
833
- ### 4.5 limiter
834
-
835
- **Versão:** 3.0.0
836
- **Descrição:** Rate limiting simples baseado em Redis
837
- **Última atualização:** 2022
838
-
839
- ```javascript
840
- import { RateLimiterRedis } from 'limiter';
841
- import Redis from 'ioredis';
842
-
843
- const redis = new Redis();
844
-
845
- const limiter = new RateLimiterRedis({
846
- storeClient: redis,
847
- keyPrefix: 'rl',
848
- points: 100, // 100 requests
849
- duration: 60, // por 60 segundos
850
- blockDuration: 60, // bloquear por 60 segundos se exceder
851
- });
852
-
853
- // Consumir pontos
854
- try {
855
- await limiter.consume('user123');
856
- const response = await fetch('https://example.com');
857
- return response.json();
858
- } catch (rateLimiterRes) {
859
- const retryAfter = Math.ceil(rateLimiterRes.msBeforeNext / 1000);
860
- console.log(`Rate limited. Retry after ${retryAfter}s`);
861
- throw new Error(`Rate limited. Retry after ${retryAfter}s`);
862
- }
863
-
864
- // Verificar pontos restantes
865
- const resRateLimiter = await limiter.get('user123');
866
- console.log(`Points remaining: ${resRateLimiter.remainingPoints}`);
867
- ```
868
-
869
- ### 4.6 rate-limiter-flexible
870
-
871
- **Versão:** 11.1.0
872
- **Descrição:** Rate limiting flexível e robusto
873
- **Última atualização:** 2024
874
-
875
- ```javascript
876
- import { RateLimiterRedis, RateLimiterMemory } from 'rate-limiter-flexible';
877
-
878
- // Rate limiter em memória
879
- const rateLimiter = new RateLimiterMemory({
880
- points: 100, // 100 requests
881
- duration: 60, // por 60 segundos
882
- });
883
-
884
- // Rate limiter com Redis
885
- const redisRateLimiter = new RateLimiterRedis({
886
- points: 100,
887
- duration: 60,
888
- storeClient: redisClient,
889
- keyPrefix: 'rl',
890
- });
891
-
892
- // Consumir pontos
893
- try {
894
- const res = await rateLimiter.consume('user123');
895
- console.log(`Points remaining: ${res.remainingPoints}`);
896
- console.log(`Retry after: ${res.msBeforeNext}ms`);
897
- } catch (rejRes) {
898
- console.log(`Rate limited. Retry after ${rejRes.msBeforeNext}ms`);
899
- }
900
-
901
- // Bloquear IP após múltiplas falhas
902
- const rateLimiterBlock = new RateLimiterMemory({
903
- points: 1,
904
- duration: 1,
905
- blockDuration: 3600, // Bloquear por 1 hora
906
- });
907
-
908
- // Rate limiting com sliding window
909
- const slidingWindowLimiter = new RateLimiterMemory({
910
- points: 100,
911
- duration: 60,
912
- execEvenly: true, // Executar均匀mente
913
- execEvenlyMinDelayMs: 100, // Mínimo 100ms entre requests
914
- });
915
- ```
916
-
917
- ---
918
-
919
- ## 5. Rate Limiting por Domínio
920
-
921
- ### 5.1 Implementação com Map
922
-
923
- ```javascript
924
- import { RateLimiterMemory } from 'rate-limiter-flexible';
925
-
926
- class DomainRateLimiter {
927
- constructor(defaults = {}) {
928
- this.limiters = new Map();
929
- this.defaults = {
930
- points: defaults.points || 100,
931
- duration: defaults.duration || 60,
932
- blockDuration: defaults.blockDuration || 0,
933
- };
934
- }
935
-
936
- getLimiter(domain) {
937
- if (!this.limiters.has(domain)) {
938
- this.limiters.set(domain, new RateLimiterMemory({
939
- points: this.defaults.points,
940
- duration: this.defaults.duration,
941
- blockDuration: this.defaults.blockDuration,
942
- }));
943
- }
944
- return this.limiters.get(domain);
945
- }
946
-
947
- async consume(domain, key = 'default', points = 1) {
948
- const limiter = this.getLimiter(domain);
949
- try {
950
- const res = await limiter.consume(key, points);
951
- return { allowed: true, remaining: res.remainingPoints };
952
- } catch (rejRes) {
953
- return {
954
- allowed: false,
955
- retryAfter: Math.ceil(rejRes.msBeforeNext / 1000),
956
- remaining: 0,
957
- };
958
- }
959
- }
960
-
961
- async reset(domain, key = 'default') {
962
- const limiter = this.getLimiter(domain);
963
- await limiter.delete(key);
964
- }
965
- }
966
-
967
- // Uso
968
- const limiter = new DomainRateLimiter({
969
- points: 100,
970
- duration: 60,
971
- });
972
-
973
- async function fetchWithRateLimit(url) {
974
- const domain = new URL(url).hostname;
975
- const result = await limiter.consume(domain);
976
-
977
- if (!result.allowed) {
978
- console.log(`Rate limited by ${domain}. Retry after ${result.retryAfter}s`);
979
- throw new Error(`Rate limited. Retry after ${result.retryAfter}s`);
980
- }
981
-
982
- return await fetch(url);
983
- }
984
- ```
985
-
986
- ### 5.2 Implementação com Crawlee
987
-
988
- ```javascript
989
- import { PlaywrightCrawler } from 'crawlee';
990
-
991
- class CrawleeDomainRateLimiter {
992
- constructor(limits = {}) {
993
- this.limits = limits;
994
- this.domainRequests = new Map();
995
- this.domainWindows = new Map();
996
- }
997
-
998
- getLimitForDomain(domain) {
999
- return this.limits[domain] || { requestsPerMinute: 60 };
1000
- }
1001
-
1002
- async checkRateLimit(domain) {
1003
- const limit = this.getLimitForDomain(domain);
1004
- const now = Date.now();
1005
- const windowStart = now - 60000;
1006
-
1007
- if (!this.domainWindows.has(domain)) {
1008
- this.domainWindows.set(domain, []);
1009
- }
1010
-
1011
- const requests = this.domainWindows.get(domain)
1012
- .filter(time => time > windowStart);
1013
-
1014
- this.domainWindows.set(domain, requests);
1015
-
1016
- if (requests.length >= limit.requestsPerMinute) {
1017
- const oldestRequest = requests[0];
1018
- const retryAfter = Math.ceil((oldestRequest + 60000 - now) / 1000);
1019
- return { allowed: false, retryAfter };
1020
- }
1021
-
1022
- requests.push(now);
1023
- return { allowed: true, remaining: limit.requestsPerMinute - requests.length };
1024
- }
1025
- }
1026
-
1027
- // Uso com Crawlee
1028
- const rateLimiter = new CrawleeDomainRateLimiter({
1029
- 'example.com': { requestsPerMinute: 30 },
1030
- 'api.example.com': { requestsPerMinute: 10 },
1031
- 'default': { requestsPerMinute: 60 },
1032
- });
1033
-
1034
- const crawler = new PlaywrightCrawler({
1035
- requestHandler: async ({ request, page }) => {
1036
- const domain = new URL(request.url).hostname;
1037
- const rateCheck = await rateLimiter.checkRateLimit(domain);
1038
-
1039
- if (!rateCheck.allowed) {
1040
- console.log(`Rate limited. Retry after ${rateCheck.retryAfter}s`);
1041
- await page.waitForTimeout(rateCheck.retryAfter * 1000);
1042
- }
1043
-
1044
- await page.goto(request.url);
1045
- return { title: await page.title() };
1046
- },
1047
- });
1048
- ```
1049
-
1050
- ### 5.3 Configuração por Endpoint
1051
-
1052
- ```javascript
1053
- import { RateLimiterMemory } from 'rate-limiter-flexible';
1054
-
1055
- const endpointLimits = {
1056
- 'api.example.com': {
1057
- '/search': { points: 10, duration: 60 },
1058
- '/users': { points: 100, duration: 60 },
1059
- '/posts': { points: 50, duration: 60 },
1060
- },
1061
- 'cdn.example.com': {
1062
- '/images': { points: 1000, duration: 60 },
1063
- '/videos': { points: 100, duration: 60 },
1064
- },
1065
- };
1066
-
1067
- class EndpointRateLimiter {
1068
- constructor(limits) {
1069
- this.limits = limits;
1070
- this.limiters = new Map();
1071
- }
1072
-
1073
- getLimiter(domain, path) {
1074
- const key = `${domain}:${path}`;
1075
- if (!this.limiters.has(key)) {
1076
- const limit = this.limits[domain]?.[path] || { points: 60, duration: 60 };
1077
- this.limiters.set(key, new RateLimiterMemory(limit));
1078
- }
1079
- return this.limiters.get(key);
1080
- }
1081
-
1082
- async consume(domain, path) {
1083
- const limiter = this.getLimiter(domain, path);
1084
- try {
1085
- const res = await limiter.consume();
1086
- return { allowed: true, remaining: res.remainingPoints };
1087
- } catch (rejRes) {
1088
- return {
1089
- allowed: false,
1090
- retryAfter: Math.ceil(rejRes.msBeforeNext / 1000),
1091
- };
1092
- }
1093
- }
1094
- }
1095
-
1096
- // Uso
1097
- const limiter = new EndpointRateLimiter(endpointLimits);
1098
-
1099
- async function apiCall(url) {
1100
- const urlObj = new URL(url);
1101
- const result = await limiter.consume(urlObj.hostname, urlObj.pathname);
1102
-
1103
- if (!result.allowed) {
1104
- throw new Error(`Rate limited. Retry after ${result.retryAfter}s`);
1105
- }
1106
-
1107
- return await fetch(url);
1108
- }
1109
- ```
1110
-
1111
- ---
1112
-
1113
- ## 6. Status Codes para Retry
1114
-
1115
- ### Status Codes para RETRY
1116
-
1117
- | Status | Descrição | Estratégia |
1118
- |--------|-----------|------------|
1119
- | **429** | Too Many Requests | Retry com Retry-After |
1120
- | **500** | Internal Server Error | Retry com backoff |
1121
- | **502** | Bad Gateway | Retry com backoff |
1122
- | **503** | Service Unavailable | Retry com Retry-After |
1123
- | **504** | Gateway Timeout | Retry com backoff |
1124
- | **408** | Request Timeout | Retry com backoff |
1125
- | **409** | Conflict | Retry (pode ser temporário) |
1126
- | **520-530** | Cloudflare Errors | Retry com backoff |
1127
-
1128
- ### Status Codes NÃO Retry
1129
-
1130
- | Status | Descrição | Ação |
1131
- |--------|-----------|------|
1132
- | **400** | Bad Request | Corrigir request |
1133
- | **401** | Unauthorized | Autenticar |
1134
- | **403** | Forbidden | Verificar permissões |
1135
- | **404** | Not Found | Verificar URL |
1136
- | **410** | Gone | Não existe mais |
1137
- | **422** | Unprocessable Entity | Corrigir dados |
1138
- | **451** | Unavailable For Legal Reasons | Não retry |
1139
- | **407** | Proxy Authentication Required | Autenticar proxy |
1140
- | **426** | Upgrade Required | Atualizar protocolo |
1141
-
1142
- ### Implementação de Decisão de Retry
1143
-
1144
- ```javascript
1145
- function shouldRetry(error) {
1146
- // Retry em erros de rede
1147
- if (error.code === 'ECONNRESET' ||
1148
- error.code === 'ECONNREFUSED' ||
1149
- error.code === 'ETIMEDOUT' ||
1150
- error.code === 'ENOTFOUND') {
1151
- return true;
1152
- }
1153
-
1154
- // Retry em status codes específicos
1155
- if (error.status) {
1156
- const retryableStatuses = [429, 500, 502, 503, 504, 408, 409];
1157
- if (retryableStatuses.includes(error.status)) {
1158
- return true;
1159
- }
1160
- }
1161
-
1162
- // Não retry em erros de autenticação
1163
- if (error.status === 401 || error.status === 403) {
1164
- return false;
1165
- }
1166
-
1167
- // Não retry em erros de validação
1168
- if (error.status === 400 || error.status === 422) {
1169
- return false;
1170
- }
1171
-
1172
- return false;
1173
- }
1174
-
1175
- // Usar com retry
1176
- import pRetry from 'p-retry';
1177
-
1178
- const result = await pRetry(async () => {
1179
- const response = await fetch('https://example.com');
1180
-
1181
- if (!response.ok) {
1182
- const error = new Error(`HTTP ${response.status}`);
1183
- error.status = response.status;
1184
- throw error;
1185
- }
1186
-
1187
- return response.json();
1188
- }, {
1189
- retries: 5,
1190
- onFailedAttempt: async (error) => {
1191
- if (!shouldRetry(error)) {
1192
- throw new pRetry.AbortError(error);
1193
- }
1194
- },
1195
- });
1196
- ```
1197
-
1198
- ---
1199
-
1200
- ## 7. Respeitando Retry-After
1201
-
1202
- ### Implementação Básica
1203
-
1204
- ```javascript
1205
- import pRetry from 'p-retry';
1206
-
1207
- async function fetchWithRetryAfter(url) {
1208
- return pRetry(async (attempt) => {
1209
- const response = await fetch(url);
1210
-
1211
- if (response.status === 429) {
1212
- const retryAfter = response.headers.get('Retry-After');
1213
-
1214
- if (retryAfter) {
1215
- // Retry-After pode ser:
1216
- // 1. Número de segundos: "120"
1217
- // 2. HTTP-date: "Wed, 21 Oct 2015 07:28:00 GMT"
1218
- let delay;
1219
-
1220
- if (isNaN(retryAfter)) {
1221
- // É uma data HTTP
1222
- const retryDate = new Date(retryAfter);
1223
- delay = retryDate.getTime() - Date.now();
1224
- } else {
1225
- // É um número de segundos
1226
- delay = parseInt(retryAfter) * 1000;
1227
- }
1228
-
1229
- console.log(`Rate limited. Waiting ${delay}ms`);
1230
- await new Promise(resolve => setTimeout(resolve, delay));
1231
- }
1232
-
1233
- throw new Error(`Rate limited (429)`);
1234
- }
1235
-
1236
- if (!response.ok) {
1237
- throw new Error(`HTTP ${response.status}`);
1238
- }
1239
-
1240
- return response.json();
1241
- }, {
1242
- retries: 5,
1243
- minTimeout: 1000,
1244
- maxTimeout: 60000,
1245
- });
1246
- }
1247
- ```
1248
-
1249
- ### Implementação Avançada com Crawlee
1250
-
1251
- ```javascript
1252
- import { PlaywrightCrawler } from 'crawlee';
1253
-
1254
- class RetryAfterHandler {
1255
- constructor() {
1256
- this.retryAfterCache = new Map();
1257
- }
1258
-
1259
- async handleRetryAfter(request, response) {
1260
- const retryAfter = response.headers.get('Retry-After');
1261
-
1262
- if (retryAfter) {
1263
- let delay;
1264
-
1265
- if (isNaN(retryAfter)) {
1266
- const retryDate = new Date(retryAfter);
1267
- delay = Math.max(0, retryDate.getTime() - Date.now());
1268
- } else {
1269
- delay = parseInt(retryAfter) * 1000;
1270
- }
1271
-
1272
- // Adicionar margem de segurança (10%)
1273
- delay = Math.ceil(delay * 1.1);
1274
-
1275
- this.retryAfterCache.set(request.url, {
1276
- delay,
1277
- timestamp: Date.now(),
1278
- });
1279
-
1280
- return delay;
1281
- }
1282
-
1283
- return null;
1284
- }
1285
-
1286
- getDelay(url) {
1287
- const cached = this.retryAfterCache.get(url);
1288
- if (cached && Date.now() - cached.timestamp < cached.delay) {
1289
- return cached.delay - (Date.now() - cached.timestamp);
1290
- }
1291
- return null;
1292
- }
1293
- }
1294
-
1295
- // Usar com Crawlee
1296
- const retryHandler = new RetryAfterHandler();
1297
-
1298
- const crawler = new PlaywrightCrawler({
1299
- requestHandler: async ({ request, page, response }) => {
1300
- // Verificar Retry-After
1301
- const delay = await retryHandler.handleRetryAfter(request, response);
1302
-
1303
- if (delay) {
1304
- console.log(`Waiting ${delay}ms for Retry-After`);
1305
- await page.waitForTimeout(delay);
1306
- }
1307
-
1308
- await page.goto(request.url);
1309
- return { title: await page.title() };
1310
- },
1311
- });
1312
- ```
1313
-
1314
- ### Retry-After com Múltiplos Headers
1315
-
1316
- ```javascript
1317
- async function parseRetryAfter(response) {
1318
- const retryAfter = response.headers.get('Retry-After');
1319
- const xRetryAfter = response.headers.get('X-Retry-After');
1320
- const rateLimitReset = response.headers.get('X-Rate-Limit-Reset');
1321
- const rateLimitRemaining = response.headers.get('X-Rate-Limit-Remaining');
1322
-
1323
- // Prioridade: Retry-After > X-Retry-After > X-Rate-Limit-Reset
1324
- if (retryAfter) {
1325
- return parseRetryHeaderValue(retryAfter);
1326
- }
1327
-
1328
- if (xRetryAfter) {
1329
- return parseRetryHeaderValue(xRetryAfter);
1330
- }
1331
-
1332
- if (rateLimitReset) {
1333
- const resetTime = parseInt(rateLimitReset) * 1000;
1334
- return Math.max(0, resetTime - Date.now());
1335
- }
1336
-
1337
- return null;
1338
- }
1339
-
1340
- function parseRetryHeaderValue(value) {
1341
- if (isNaN(value)) {
1342
- // HTTP-date
1343
- const retryDate = new Date(value);
1344
- return Math.max(0, retryDate.getTime() - Date.now());
1345
- }
1346
- // Seconds
1347
- return parseInt(value) * 1000;
1348
- }
1349
- ```
1350
-
1351
- ---
1352
-
1353
- ## 8. Retry com Proxy Rotation
1354
-
1355
- ### Padrão Básico
1356
-
1357
- ```javascript
1358
- import pRetry from 'p-retry';
1359
-
1360
- class RetryWithProxyRotation {
1361
- constructor(proxies) {
1362
- this.proxies = proxies;
1363
- this.currentIndex = 0;
1364
- }
1365
-
1366
- getNextProxy() {
1367
- const proxy = this.proxies[this.currentIndex % this.proxies.length];
1368
- this.currentIndex++;
1369
- return proxy;
1370
- }
1371
-
1372
- async fetchWithRetry(url, options = {}) {
1373
- return pRetry(async (attempt) => {
1374
- const proxy = this.getNextProxy();
1375
- console.log(`Attempt ${attempt} using proxy ${proxy}`);
1376
-
1377
- const controller = new AbortController();
1378
- const timeoutId = setTimeout(() => controller.abort(), options.timeout || 10000);
1379
-
1380
- try {
1381
- const response = await fetch(url, {
1382
- ...options,
1383
- signal: controller.signal,
1384
- dispatcher: this.createAgent(proxy),
1385
- });
1386
-
1387
- clearTimeout(timeoutId);
1388
-
1389
- if (!response.ok) {
1390
- const error = new Error(`HTTP ${response.status}`);
1391
- error.status = response.status;
1392
- throw error;
1393
- }
1394
-
1395
- return response.json();
1396
- } catch (error) {
1397
- clearTimeout(timeoutId);
1398
- throw error;
1399
- }
1400
- }, {
1401
- retries: options.retries || 3,
1402
- minTimeout: options.minTimeout || 1000,
1403
- maxTimeout: options.maxTimeout || 10000,
1404
- onFailedAttempt: async (error) => {
1405
- console.log(`Attempt ${error.attemptNumber} failed: ${error.message}`);
1406
- if (error.retriesLeft === 0) {
1407
- throw new pRetry.AbortError(error);
1408
- }
1409
- },
1410
- });
1411
- }
1412
-
1413
- createAgent(proxy) {
1414
- if (proxy.startsWith('socks')) {
1415
- const { SocksProxyAgent } = require('socks-proxy-agent');
1416
- return new SocksProxyAgent(proxy);
1417
- }
1418
- const { HttpsProxyAgent } = require('https-proxy-agent');
1419
- return new HttpsProxyAgent(proxy);
1420
- }
1421
- }
1422
-
1423
- // Uso
1424
- const fetcher = new RetryWithProxyRotation([
1425
- 'http://proxy1.com:8080',
1426
- 'http://proxy2.com:8080',
1427
- 'http://proxy3.com:8080',
1428
- ]);
1429
-
1430
- const result = await fetcher.fetchWithRetry('https://example.com/api', {
1431
- retries: 5,
1432
- timeout: 10000,
1433
- });
1434
- ```
1435
-
1436
- ### Padrão com Status Codes
1437
-
1438
- ```javascript
1439
- import pRetry from 'p-retry';
1440
-
1441
- class SmartRetryWithProxy {
1442
- constructor(proxies, options = {}) {
1443
- this.proxies = proxies;
1444
- this.currentIndex = 0;
1445
- this.retryableStatuses = options.retryableStatuses || [429, 500, 502, 503, 504];
1446
- this.proxyFailureThreshold = options.proxyFailureThreshold || 3;
1447
- this.proxyFailures = new Map();
1448
- }
1449
-
1450
- getNextProxy() {
1451
- // Filtrar proxies com muitas falhas
1452
- const availableProxies = this.proxies.filter(proxy => {
1453
- const failures = this.proxyFailures.get(proxy) || 0;
1454
- return failures < this.proxyFailureThreshold;
1455
- });
1456
-
1457
- if (availableProxies.length === 0) {
1458
- // Resetar contadores de falha
1459
- this.proxyFailures.clear();
1460
- return this.proxies[0];
1461
- }
1462
-
1463
- const proxy = availableProxies[this.currentIndex % availableProxies.length];
1464
- this.currentIndex++;
1465
- return proxy;
1466
- }
1467
-
1468
- reportProxyFailure(proxy) {
1469
- const failures = this.proxyFailures.get(proxy) || 0;
1470
- this.proxyFailures.set(proxy, failures + 1);
1471
- }
1472
-
1473
- async fetchWithRetry(url, options = {}) {
1474
- return pRetry(async (attempt) => {
1475
- const proxy = this.getNextProxy();
1476
- console.log(`Attempt ${attempt} using proxy ${proxy}`);
1477
-
1478
- try {
1479
- const response = await fetch(url, {
1480
- ...options,
1481
- dispatcher: this.createAgent(proxy),
1482
- });
1483
-
1484
- if (!response.ok) {
1485
- const error = new Error(`HTTP ${response.status}`);
1486
- error.status = response.status;
1487
- error.proxy = proxy;
1488
- throw error;
1489
- }
1490
-
1491
- return response.json();
1492
- } catch (error) {
1493
- if (error.status && !this.retryableStatuses.includes(error.status)) {
1494
- throw new pRetry.AbortError(error);
1495
- }
1496
-
1497
- if (error.proxy) {
1498
- this.reportProxyFailure(error.proxy);
1499
- }
1500
-
1501
- throw error;
1502
- }
1503
- }, {
1504
- retries: options.retries || 5,
1505
- minTimeout: options.minTimeout || 1000,
1506
- maxTimeout: options.maxTimeout || 30000,
1507
- randomize: true,
1508
- onFailedAttempt: async (error) => {
1509
- console.log(`Attempt ${error.attemptNumber} failed: ${error.message}`);
1510
- },
1511
- });
1512
- }
1513
-
1514
- createAgent(proxy) {
1515
- if (proxy.startsWith('socks')) {
1516
- const { SocksProxyAgent } = require('socks-proxy-agent');
1517
- return new SocksProxyAgent(proxy);
1518
- }
1519
- const { HttpsProxyAgent } = require('https-proxy-agent');
1520
- return new HttpsProxyAgent(proxy);
1521
- }
1522
- }
1523
-
1524
- // Uso
1525
- const fetcher = new SmartRetryWithProxy([
1526
- 'http://proxy1.com:8080',
1527
- 'http://proxy2.com:8080',
1528
- 'socks5://proxy3.com:1080',
1529
- ], {
1530
- retryableStatuses: [429, 500, 502, 503, 504],
1531
- proxyFailureThreshold: 3,
1532
- });
1533
-
1534
- const result = await fetcher.fetchWithRetry('https://example.com/api');
1535
- ```
1536
-
1537
- ### Padrão com Crawlee
1538
-
1539
- ```javascript
1540
- import { PlaywrightCrawler, ProxyConfiguration } from 'crawlee';
1541
-
1542
- class CrawleeRetryWithProxy {
1543
- constructor(proxies) {
1544
- this.proxies = proxies;
1545
- this.currentIndex = 0;
1546
- this.proxyFailures = new Map();
1547
- }
1548
-
1549
- getNextProxy() {
1550
- const availableProxies = this.proxies.filter(proxy => {
1551
- const failures = this.proxyFailures.get(proxy) || 0;
1552
- return failures < 3;
1553
- });
1554
-
1555
- if (availableProxies.length === 0) {
1556
- this.proxyFailures.clear();
1557
- return this.proxies[0];
1558
- }
1559
-
1560
- const proxy = availableProxies[this.currentIndex % availableProxies.length];
1561
- this.currentIndex++;
1562
- return proxy;
1563
- }
1564
-
1565
- reportFailure(proxy) {
1566
- const failures = this.proxyFailures.get(proxy) || 0;
1567
- this.proxyFailures.set(proxy, failures + 1);
1568
- }
1569
-
1570
- getCrawlerOptions() {
1571
- return {
1572
- proxyConfiguration: new ProxyConfiguration({
1573
- newUrlFunction: () => this.getNextProxy(),
1574
- }),
1575
- retryOnBlocked: true,
1576
- maxRequestRetries: 5,
1577
- requestHandlerTimeoutSecs: 30,
1578
- requestHandler: async ({ request, page, proxyInfo }) => {
1579
- try {
1580
- await page.goto(request.url, { timeout: 30000 });
1581
- const title = await page.title();
1582
- return { url: request.url, title };
1583
- } catch (error) {
1584
- this.reportFailure(proxyInfo.url);
1585
- throw error;
1586
- }
1587
- },
1588
- };
1589
- }
1590
- }
1591
-
1592
- // Uso
1593
- const retryProxy = new CrawleeRetryWithProxy([
1594
- 'http://proxy1.com:8080',
1595
- 'http://proxy2.com:8080',
1596
- 'socks5://proxy3.com:1080',
1597
- ]);
1598
-
1599
- const crawler = new PlaywrightCrawler(retryProxy.getCrawlerOptions());
1600
- await crawler.run(['https://example.com']);
1601
- ```
1602
-
1603
- ---
1604
-
1605
- ## 9. Exemplos Completos
1606
-
1607
- ### 9.1 Exemplo Completo: Retry com Rate Limiting
1608
-
1609
- ```javascript
1610
- import pRetry from 'p-retry';
1611
- import { RateLimiterMemory } from 'rate-limiter-flexible';
1612
-
1613
- class ResilientFetcher {
1614
- constructor(options = {}) {
1615
- this.rateLimiter = new RateLimiterMemory({
1616
- points: options.rateLimit?.points || 10,
1617
- duration: options.rateLimit?.duration || 1,
1618
- });
1619
-
1620
- this.retryOptions = {
1621
- retries: options.retries || 5,
1622
- minTimeout: options.minTimeout || 1000,
1623
- maxTimeout: options.maxTimeout || 30000,
1624
- randomize: options.randomize ?? true,
1625
- };
1626
-
1627
- this.retryableStatuses = options.retryableStatuses || [429, 500, 502, 503, 504];
1628
- }
1629
-
1630
- async fetch(url, options = {}) {
1631
- // Rate limiting
1632
- const domain = new URL(url).hostname;
1633
- try {
1634
- await this.rateLimiter.consume(domain);
1635
- } catch (rejRes) {
1636
- const retryAfter = Math.ceil(rejRes.msBeforeNext / 1000);
1637
- console.log(`Rate limited by ${domain}. Waiting ${retryAfter}s`);
1638
- await this.sleep(retryAfter * 1000);
1639
- }
1640
-
1641
- // Retry logic
1642
- return pRetry(async (attempt) => {
1643
- console.log(`Attempt ${attempt} for ${url}`);
1644
-
1645
- const controller = new AbortController();
1646
- const timeoutId = setTimeout(() => controller.abort(), options.timeout || 10000);
1647
-
1648
- try {
1649
- const response = await fetch(url, {
1650
- ...options,
1651
- signal: controller.signal,
1652
- });
1653
-
1654
- clearTimeout(timeoutId);
1655
-
1656
- // Tratar Retry-After
1657
- if (response.status === 429) {
1658
- const retryAfter = response.headers.get('Retry-After');
1659
- if (retryAfter) {
1660
- const delay = this.parseRetryAfter(retryAfter);
1661
- console.log(`Retry-After: ${delay}ms`);
1662
- await this.sleep(delay);
1663
- }
1664
- throw new Error(`Rate limited (429)`);
1665
- }
1666
-
1667
- if (!response.ok) {
1668
- const error = new Error(`HTTP ${response.status}`);
1669
- error.status = response.status;
1670
- throw error;
1671
- }
1672
-
1673
- return response.json();
1674
- } catch (error) {
1675
- clearTimeout(timeoutId);
1676
-
1677
- // Não retry em erros não retryable
1678
- if (error.status && !this.retryableStatuses.includes(error.status)) {
1679
- throw new pRetry.AbortError(error);
1680
- }
1681
-
1682
- throw error;
1683
- }
1684
- }, {
1685
- ...this.retryOptions,
1686
- onFailedAttempt: async (error) => {
1687
- console.log(`Attempt ${error.attemptNumber} failed: ${error.message}`);
1688
- console.log(`Retries left: ${error.retriesLeft}`);
1689
- },
1690
- });
1691
- }
1692
-
1693
- parseRetryAfter(value) {
1694
- if (isNaN(value)) {
1695
- const retryDate = new Date(value);
1696
- return Math.max(0, retryDate.getTime() - Date.now());
1697
- }
1698
- return parseInt(value) * 1000;
1699
- }
1700
-
1701
- sleep(ms) {
1702
- return new Promise(resolve => setTimeout(resolve, ms));
1703
- }
1704
- }
1705
-
1706
- // Uso
1707
- const fetcher = new ResilientFetcher({
1708
- rateLimit: { points: 10, duration: 1 },
1709
- retries: 5,
1710
- minTimeout: 1000,
1711
- maxTimeout: 30000,
1712
- retryableStatuses: [429, 500, 502, 503, 504],
1713
- });
1714
-
1715
- const result = await fetcher.fetch('https://api.example.com/data');
1716
- ```
1717
-
1718
- ### 9.2 Exemplo Completo: Crawlee com Rate Limiting e Retry
1719
-
1720
- ```javascript
1721
- import { PlaywrightCrawler, ProxyConfiguration } from 'crawlee';
1722
- import { RateLimiterMemory } from 'rate-limiter-flexible';
1723
-
1724
- class ProductionScraper {
1725
- constructor(options = {}) {
1726
- this.proxies = options.proxies || [];
1727
- this.proxyIndex = 0;
1728
- this.proxyFailures = new Map();
1729
- this.rateLimiters = new Map();
1730
- this.defaultRateLimit = options.rateLimit || { points: 60, duration: 60 };
1731
- }
1732
-
1733
- getProxy() {
1734
- const available = this.proxies.filter(p =>
1735
- (this.proxyFailures.get(p) || 0) < 3
1736
- );
1737
-
1738
- if (available.length === 0) {
1739
- this.proxyFailures.clear();
1740
- return this.proxies[0];
1741
- }
1742
-
1743
- const proxy = available[this.proxyIndex % available.length];
1744
- this.proxyIndex++;
1745
- return proxy;
1746
- }
1747
-
1748
- reportProxyFailure(proxy) {
1749
- const failures = this.proxyFailures.get(proxy) || 0;
1750
- this.proxyFailures.set(proxy, failures + 1);
1751
- }
1752
-
1753
- getRateLimiter(domain) {
1754
- if (!this.rateLimiters.has(domain)) {
1755
- this.rateLimiters.set(domain, new RateLimiterMemory(this.defaultRateLimit));
1756
- }
1757
- return this.rateLimiters.get(domain);
1758
- }
1759
-
1760
- async checkRateLimit(domain) {
1761
- const limiter = this.getRateLimiter(domain);
1762
- try {
1763
- await limiter.consume();
1764
- return { allowed: true };
1765
- } catch (rejRes) {
1766
- return {
1767
- allowed: false,
1768
- retryAfter: Math.ceil(rejRes.msBeforeNext / 1000),
1769
- };
1770
- }
1771
- }
1772
-
1773
- getCrawlerOptions() {
1774
- return {
1775
- proxyConfiguration: new ProxyConfiguration({
1776
- newUrlFunction: () => this.getProxy(),
1777
- }),
1778
- retryOnBlocked: true,
1779
- maxRequestRetries: 5,
1780
- requestHandlerTimeoutSecs: 30,
1781
- requestHandler: async ({ request, page, proxyInfo }) => {
1782
- const domain = new URL(request.url).hostname;
1783
-
1784
- // Rate limiting
1785
- const rateCheck = await this.checkRateLimit(domain);
1786
- if (!rateCheck.allowed) {
1787
- console.log(`Rate limited. Waiting ${rateCheck.retryAfter}s`);
1788
- await page.waitForTimeout(rateCheck.retryAfter * 1000);
1789
- }
1790
-
1791
- try {
1792
- await page.goto(request.url, { timeout: 30000 });
1793
-
1794
- // Extrair dados
1795
- const title = await page.title();
1796
- const content = await page.textContent('body');
1797
-
1798
- return { url: request.url, title, content };
1799
- } catch (error) {
1800
- if (proxyInfo?.url) {
1801
- this.reportProxyFailure(proxyInfo.url);
1802
- }
1803
- throw error;
1804
- }
1805
- },
1806
- };
1807
- }
1808
-
1809
- async scrape(urls) {
1810
- const crawler = new PlaywrightCrawler(this.getCrawlerOptions());
1811
- await crawler.run(urls);
1812
-
1813
- // Estatísticas
1814
- console.log('Scraping completed');
1815
- console.log('Proxy failures:', Object.fromEntries(this.proxyFailures));
1816
- }
1817
- }
1818
-
1819
- // Uso
1820
- const scraper = new ProductionScraper({
1821
- proxies: [
1822
- 'http://proxy1.com:8080',
1823
- 'http://proxy2.com:8080',
1824
- 'socks5://proxy3.com:1080',
1825
- ],
1826
- rateLimit: { points: 60, duration: 60 },
1827
- });
1828
-
1829
- await scraper.scrape([
1830
- 'https://example.com/page1',
1831
- 'https://example.com/page2',
1832
- 'https://example.com/page3',
1833
- ]);
1834
- ```
1835
-
1836
- ### 9.3 Exemplo Completo: Sistema de Retry com Circuit Breaker
1837
-
1838
- ```javascript
1839
- import pRetry from 'p-retry';
1840
-
1841
- class CircuitBreaker {
1842
- constructor(options = {}) {
1843
- this.failureThreshold = options.failureThreshold || 5;
1844
- this.resetTimeout = options.resetTimeout || 60000;
1845
- this.state = 'CLOSED';
1846
- this.failureCount = 0;
1847
- this.lastFailureTime = null;
1848
- }
1849
-
1850
- async execute(fn) {
1851
- if (this.state === 'OPEN') {
1852
- if (Date.now() - this.lastFailureTime >= this.resetTimeout) {
1853
- this.state = 'HALF_OPEN';
1854
- } else {
1855
- throw new Error('Circuit breaker is OPEN');
1856
- }
1857
- }
1858
-
1859
- try {
1860
- const result = await fn();
1861
- this.onSuccess();
1862
- return result;
1863
- } catch (error) {
1864
- this.onFailure();
1865
- throw error;
1866
- }
1867
- }
1868
-
1869
- onSuccess() {
1870
- this.failureCount = 0;
1871
- this.state = 'CLOSED';
1872
- }
1873
-
1874
- onFailure() {
1875
- this.failureCount++;
1876
- this.lastFailureTime = Date.now();
1877
-
1878
- if (this.failureCount >= this.failureThreshold) {
1879
- this.state = 'OPEN';
1880
- }
1881
- }
1882
-
1883
- getState() {
1884
- return {
1885
- state: this.state,
1886
- failureCount: this.failureCount,
1887
- lastFailureTime: this.lastFailureTime,
1888
- };
1889
- }
1890
- }
1891
-
1892
- class ResilientFetcher {
1893
- constructor(options = {}) {
1894
- this.circuitBreaker = new CircuitBreaker({
1895
- failureThreshold: options.failureThreshold || 5,
1896
- resetTimeout: options.resetTimeout || 60000,
1897
- });
1898
-
1899
- this.retryOptions = {
1900
- retries: options.retries || 3,
1901
- minTimeout: options.minTimeout || 1000,
1902
- maxTimeout: options.maxTimeout || 10000,
1903
- };
1904
- }
1905
-
1906
- async fetch(url, options = {}) {
1907
- return this.circuitBreaker.execute(async () => {
1908
- return pRetry(async (attempt) => {
1909
- console.log(`Attempt ${attempt} for ${url}`);
1910
-
1911
- const response = await fetch(url, options);
1912
-
1913
- if (!response.ok) {
1914
- const error = new Error(`HTTP ${response.status}`);
1915
- error.status = response.status;
1916
- throw error;
1917
- }
1918
-
1919
- return response.json();
1920
- }, this.retryOptions);
1921
- });
1922
- }
1923
-
1924
- getState() {
1925
- return this.circuitBreaker.getState();
1926
- }
1927
- }
1928
-
1929
- // Uso
1930
- const fetcher = new ResilientFetcher({
1931
- failureThreshold: 5,
1932
- resetTimeout: 60000,
1933
- retries: 3,
1934
- });
1935
-
1936
- try {
1937
- const result = await fetcher.fetch('https://api.example.com/data');
1938
- console.log('Success:', result);
1939
- } catch (error) {
1940
- console.log('Failed:', error.message);
1941
- console.log('Circuit breaker state:', fetcher.getState());
1942
- }
1943
- ```
1944
-
1945
- ---
1946
-
1947
- ## Referências
1948
-
1949
- 1. p-retry - https://github.com/sindresorhus/p-retry
1950
- 2. async-retry - https://github.com/vercel/async-retry
1951
- 3. retry - https://github.com/STRML/retry
1952
- 4. exponential-backoff - https://github.com/coveo/exponential-backoff
1953
- 5. bottleneck - https://github.com/SGrondin/bottleneck
1954
- 6. p-throttle - https://github.com/sindresorhus/p-throttle
1955
- 7. p-limit - https://github.com/sindresorhus/p-limit
1956
- 8. p-queue - https://github.com/sindresorhus/p-queue
1957
- 9. rate-limiter-flexible - https://github.com/animir/node-rate-limiter-flexible
1958
- 10. Crawlee Rate Limiting - https://crawlee.dev/docs/guides/avoid-blocking