2sagaco48 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (365) hide show
  1. package/diagnostics.mjs +141 -0
  2. package/dist/compute.worker-j5ahIpF-.js +1 -0
  3. package/dist/graph.worker-DG6iGCB9.js +1 -0
  4. package/dist/index.html +2314 -0
  5. package/flatten-guide.md +248 -0
  6. package/index.html +12 -0
  7. package/package.json +38 -0
  8. package/src/App.orig.tsx +204 -0
  9. package/src/App.orig1.tsx +27 -0
  10. package/src/App.orig2.tsx +25 -0
  11. package/src/App.tsx +3 -0
  12. package/src/BaseApp.tsx +18 -0
  13. package/src/INTEGRATION_LEDGER.md +22 -0
  14. package/src/PERSIST_CANARY.orig.txt +1 -0
  15. package/src/PERSIST_CANARY.txt +1 -0
  16. package/src/REGRESSION_LEDGER.md +651 -0
  17. package/src/TEMPLATE_PIPELINE_AUDIT.md +208 -0
  18. package/src/WILLIAMS_PERSONA_GUIDE.md +62 -0
  19. package/src/chat/VeritasChat.tsx +69 -0
  20. package/src/chat/synthesis.ts +31 -0
  21. package/src/chat/tier.ts +45 -0
  22. package/src/components/AdaptersPage.orig.tsx +99 -0
  23. package/src/components/AdaptersPage.tsx +3 -0
  24. package/src/components/AdversarialPanel.tsx +136 -0
  25. package/src/components/AnchorBaselinePanel.tsx +75 -0
  26. package/src/components/AnswerPanel.tsx +60 -0
  27. package/src/components/ArtifactPanel.tsx +43 -0
  28. package/src/components/ChatApp.orig.tsx +1582 -0
  29. package/src/components/ChatApp.orig1.tsx +722 -0
  30. package/src/components/ChatApp.tsx +95 -0
  31. package/src/components/ChatAugmentPanels.tsx +73 -0
  32. package/src/components/CitationLedgerPanel.tsx +313 -0
  33. package/src/components/ComputeSandboxPanel.tsx +130 -0
  34. package/src/components/ConfigPanel.tsx +110 -0
  35. package/src/components/ControlPlanePage.tsx +195 -0
  36. package/src/components/CreativeTreeLifePage.tsx +234 -0
  37. package/src/components/CreativeTreeOfLifePanel.tsx +149 -0
  38. package/src/components/DebugTracePanel.tsx +137 -0
  39. package/src/components/DeepReasoningTrace.tsx +48 -0
  40. package/src/components/EntitySheetPanel.tsx +51 -0
  41. package/src/components/FailureModesPanel.tsx +104 -0
  42. package/src/components/GBSDashboard.tsx +239 -0
  43. package/src/components/GraphView.tsx +116 -0
  44. package/src/components/HUD.tsx +125 -0
  45. package/src/components/HypothesisPanel.tsx +67 -0
  46. package/src/components/InnovationGenomeEngine.tsx +792 -0
  47. package/src/components/InnovationPersonaGuide.tsx +348 -0
  48. package/src/components/InnovationPersonaPanel.tsx +289 -0
  49. package/src/components/LiveResourceHUD.tsx +109 -0
  50. package/src/components/LongWriterPanel.tsx +112 -0
  51. package/src/components/MainPipelineV10Bridge.tsx +72 -0
  52. package/src/components/MarkdownLite.tsx +63 -0
  53. package/src/components/MemoryInspector.tsx +38 -0
  54. package/src/components/MemoryMonitor.tsx +52 -0
  55. package/src/components/MemoryStressPanel.tsx +176 -0
  56. package/src/components/ModulesPage.tsx +171 -0
  57. package/src/components/PipelineDebugConsole.orig.tsx +1856 -0
  58. package/src/components/PipelineDebugConsole.tsx +3 -0
  59. package/src/components/PreFlightHUD.tsx +67 -0
  60. package/src/components/PrismaFetchTracePanel.tsx +87 -0
  61. package/src/components/ReportOSPanel.tsx +165 -0
  62. package/src/components/ResourceEstimatorPage.tsx +327 -0
  63. package/src/components/RichText.tsx +181 -0
  64. package/src/components/SagaOsPanel.tsx +605 -0
  65. package/src/components/SagaOsReference.tsx +421 -0
  66. package/src/components/SagaOsV2Panel.tsx +594 -0
  67. package/src/components/SagaStyleTab.tsx +382 -0
  68. package/src/components/SageBlueprintPanel.tsx +416 -0
  69. package/src/components/SharedChatInput.tsx +77 -0
  70. package/src/components/StatFinancePanel.tsx +190 -0
  71. package/src/components/StylePersonaPanel.tsx +128 -0
  72. package/src/components/TemplatesPage.tsx +300 -0
  73. package/src/components/TestPanel.tsx +63 -0
  74. package/src/components/TraceLog.tsx +89 -0
  75. package/src/components/V15CalibrationAugment.tsx +1134 -0
  76. package/src/components/V15CalibrationDialog.tsx +1871 -0
  77. package/src/components/V15Overlay.orig.tsx +120 -0
  78. package/src/components/V15Overlay.tsx +4 -0
  79. package/src/components/V15OverlayWrapper.tsx +362 -0
  80. package/src/components/V15Toggle.tsx +34 -0
  81. package/src/console/DiagnosticRecoveryPanel.tsx +358 -0
  82. package/src/console/EngineeringConsole.tsx +103 -0
  83. package/src/console/FictionSystemPanels.tsx +882 -0
  84. package/src/console/InspectorPanels.tsx +254 -0
  85. package/src/console/ManuscriptGraderPanel.tsx +182 -0
  86. package/src/console/RecursiveReviserPanel.tsx +245 -0
  87. package/src/console/SeedControlPanel.tsx +135 -0
  88. package/src/console/StoryControllerPanel.tsx +443 -0
  89. package/src/console/engineBridge.ts +258 -0
  90. package/src/console/gemini.ts +106 -0
  91. package/src/console/grading.ts +250 -0
  92. package/src/console/util.ts +45 -0
  93. package/src/fiction/continuity.ts +372 -0
  94. package/src/fiction/crash-protection.ts +111 -0
  95. package/src/fiction/diagnostics.ts +208 -0
  96. package/src/fiction/diff.ts +74 -0
  97. package/src/fiction/entity-state-machine.ts +214 -0
  98. package/src/fiction/nive-engine.ts +404 -0
  99. package/src/fiction/pipeline-selftest.ts +132 -0
  100. package/src/fiction/seed-control.ts +193 -0
  101. package/src/fiction/story-engine.ts +326 -0
  102. package/src/fiction/types.ts +68 -0
  103. package/src/flatten-guide.md +379 -0
  104. package/src/index.css +14 -0
  105. package/src/index.orig.css +13 -0
  106. package/src/lib/academic-sources.base.ts +188 -0
  107. package/src/lib/academic-sources.orig.ts +28 -0
  108. package/src/lib/academic-sources.ts +10 -0
  109. package/src/lib/advanced-math.ts +119 -0
  110. package/src/lib/adversarial-engine.base.ts +409 -0
  111. package/src/lib/adversarial-engine.ts +82 -0
  112. package/src/lib/ai-revision.ts +623 -0
  113. package/src/lib/app-state.tsx +426 -0
  114. package/src/lib/artifact-registry.ts +97 -0
  115. package/src/lib/artifacts.ts +180 -0
  116. package/src/lib/atlas-dr.ts +167 -0
  117. package/src/lib/browser-mtls.ts +127 -0
  118. package/src/lib/browser-queue.ts +221 -0
  119. package/src/lib/browser-search-scraper.base.ts +382 -0
  120. package/src/lib/browser-search-scraper.orig.ts +90 -0
  121. package/src/lib/browser-search-scraper.ts +10 -0
  122. package/src/lib/calc-interceptor.ts +82 -0
  123. package/src/lib/citation-lane-tap.ts +78 -0
  124. package/src/lib/citation-ledger-store.ts +369 -0
  125. package/src/lib/citation-ledger.ts +203 -0
  126. package/src/lib/compute-sandbox.ts +215 -0
  127. package/src/lib/compute.worker.ts +153 -0
  128. package/src/lib/connectors/gemini.ts +120 -0
  129. package/src/lib/connectors/jina.ts +233 -0
  130. package/src/lib/connectors/marketdata.ts +51 -0
  131. package/src/lib/connectors/prismafetch.base.ts +175 -0
  132. package/src/lib/connectors/prismafetch.ts +1 -0
  133. package/src/lib/connectors/serpapi.ts +65 -0
  134. package/src/lib/connectors/wikidata.ts +44 -0
  135. package/src/lib/constraints.ts +331 -0
  136. package/src/lib/continuation-detector.base.ts +153 -0
  137. package/src/lib/continuation-detector.ts +48 -0
  138. package/src/lib/contradraft.ts +168 -0
  139. package/src/lib/cors-proxy.ts +120 -0
  140. package/src/lib/coverage.ts +81 -0
  141. package/src/lib/debug/architecture-prescription.ts +556 -0
  142. package/src/lib/debug/covea-repair.ts +543 -0
  143. package/src/lib/debug/helios-ground.ts +319 -0
  144. package/src/lib/debug/intent-decomposer.ts +281 -0
  145. package/src/lib/debug/intent-lattice.ts +349 -0
  146. package/src/lib/debug/pipeline-diagnosis.ts +1149 -0
  147. package/src/lib/debug/pipeline-trace-bus.ts +424 -0
  148. package/src/lib/debug/prompt-forge.ts +678 -0
  149. package/src/lib/debug/repair-sites.ts +513 -0
  150. package/src/lib/debug/research-phase.ts +266 -0
  151. package/src/lib/debug/retrieval-context.ts +76 -0
  152. package/src/lib/debug/retrieval-hardener.ts +142 -0
  153. package/src/lib/debug/scraper-debug-runner.ts +576 -0
  154. package/src/lib/debug/scraper-forensics.ts +418 -0
  155. package/src/lib/debug/scraper-lane-roadmap.ts +136 -0
  156. package/src/lib/debug/self-test.ts +415 -0
  157. package/src/lib/debug/step-attribution.ts +211 -0
  158. package/src/lib/debug/template-rubric.ts +301 -0
  159. package/src/lib/debug/unified-innovation.ts +126 -0
  160. package/src/lib/debug/veritas-hybrid-scraper.ts +335 -0
  161. package/src/lib/defense-registry.ts +104 -0
  162. package/src/lib/defenses.ts +162 -0
  163. package/src/lib/deterministic-citation-ledger.ts +174 -0
  164. package/src/lib/elo-registry.base.ts +117 -0
  165. package/src/lib/elo-registry.ts +1 -0
  166. package/src/lib/entity-resolver.ts +291 -0
  167. package/src/lib/failure-modes.ts +267 -0
  168. package/src/lib/feature-registry.ts +69 -0
  169. package/src/lib/flaw-registry.ts +143 -0
  170. package/src/lib/flaws/_template.ts +52 -0
  171. package/src/lib/flaws/builtins.ts +63 -0
  172. package/src/lib/flaws/finance.ts +169 -0
  173. package/src/lib/flaws/fixers.ts +10 -0
  174. package/src/lib/flaws/index.ts +32 -0
  175. package/src/lib/flaws/legal.ts +157 -0
  176. package/src/lib/flaws/medical.ts +188 -0
  177. package/src/lib/flaws/original-defenses-pack.ts +81 -0
  178. package/src/lib/flaws/sample-declarative-pack.json +38 -0
  179. package/src/lib/flaws/selftest.ts +201 -0
  180. package/src/lib/flaws/software-extended.ts +125 -0
  181. package/src/lib/flaws/software-rn-webgl.ts +182 -0
  182. package/src/lib/flaws/statistics-advanced.ts +46 -0
  183. package/src/lib/flaws/statistics.ts +61 -0
  184. package/src/lib/gbse/config.ts +20 -0
  185. package/src/lib/gbse/engine.ts +226 -0
  186. package/src/lib/gbse/graph.ts +118 -0
  187. package/src/lib/gbse/graph.worker.ts +21 -0
  188. package/src/lib/gbse/tests.ts +117 -0
  189. package/src/lib/gbse/tiers.ts +65 -0
  190. package/src/lib/gbse/types.ts +94 -0
  191. package/src/lib/innovation-genome-engine-v2.orig.ts +1001 -0
  192. package/src/lib/innovation-genome-engine-v2.ts +3 -0
  193. package/src/lib/innovation-genome-engine.orig.ts +330 -0
  194. package/src/lib/innovation-genome-engine.ts +3 -0
  195. package/src/lib/innovation-genome-v10.orig.ts +314 -0
  196. package/src/lib/innovation-genome-v10.ts +2 -0
  197. package/src/lib/innovation-genome-v3.orig.ts +2015 -0
  198. package/src/lib/innovation-genome-v3.ts +2 -0
  199. package/src/lib/innovation-genome-v4.orig.ts +1959 -0
  200. package/src/lib/innovation-genome-v4.ts +2 -0
  201. package/src/lib/innovation-genome-v5.orig.ts +1210 -0
  202. package/src/lib/innovation-genome-v5.ts +2 -0
  203. package/src/lib/innovation-genome-v7.orig.ts +2549 -0
  204. package/src/lib/innovation-genome-v7.ts +2 -0
  205. package/src/lib/innovation-genome-v8.orig.ts +1485 -0
  206. package/src/lib/innovation-genome-v8.ts +2 -0
  207. package/src/lib/innovation-genome-v9.orig.ts +643 -0
  208. package/src/lib/innovation-genome-v9.ts +2 -0
  209. package/src/lib/jina.base.ts +293 -0
  210. package/src/lib/jina.ts +1 -0
  211. package/src/lib/live-telemetry.ts +61 -0
  212. package/src/lib/longwriter.ts +84 -0
  213. package/src/lib/manuscript-grade-v2.ts +298 -0
  214. package/src/lib/memory-governor.ts +173 -0
  215. package/src/lib/memory-stress-tests.ts +248 -0
  216. package/src/lib/model-intelligence.ts +48 -0
  217. package/src/lib/model-rotator.ts +75 -0
  218. package/src/lib/models.orig.ts +513 -0
  219. package/src/lib/models.ts +151 -0
  220. package/src/lib/n-deep.base.ts +592 -0
  221. package/src/lib/n-deep.ts +51 -0
  222. package/src/lib/nih-simulator.ts +56 -0
  223. package/src/lib/nih-vulnerability-fixes.ts +460 -0
  224. package/src/lib/omega-templates.base.ts +294 -0
  225. package/src/lib/omega-templates.ts +225 -0
  226. package/src/lib/omni-nexus.ts +64 -0
  227. package/src/lib/oracle-adapters.ts +67 -0
  228. package/src/lib/oracle-registry.ts +163 -0
  229. package/src/lib/orchestrator.ts +357 -0
  230. package/src/lib/output-boundary.ts +235 -0
  231. package/src/lib/overrides/vite-native-chaos-harness.ts +154 -0
  232. package/src/lib/overrides/vite-native-contract-plane.ts +245 -0
  233. package/src/lib/overrides/vite-native-doctor-plane.ts +208 -0
  234. package/src/lib/overrides/vite-native-knowledge-store.ts +267 -0
  235. package/src/lib/overrides/vite-native-policy-plane.ts +190 -0
  236. package/src/lib/overrides/vite-native-replay-plane.ts +197 -0
  237. package/src/lib/overrides/vite-native-runtime-plane.ts +106 -0
  238. package/src/lib/overrides/vite-native-scraper.ts +848 -0
  239. package/src/lib/overrides/vite-native-selftest-functional.ts +217 -0
  240. package/src/lib/overrides/vite-native-selftest.ts +183 -0
  241. package/src/lib/overrides/vite-native-snapshot-plane.ts +123 -0
  242. package/src/lib/philosophy-toolkit.ts +75 -0
  243. package/src/lib/pipeline.orig.ts +659 -0
  244. package/src/lib/pipeline.ts +42 -0
  245. package/src/lib/precache.ts +128 -0
  246. package/src/lib/py-sandbox.ts +205 -0
  247. package/src/lib/quality-score.ts +96 -0
  248. package/src/lib/quant-engine.ts +231 -0
  249. package/src/lib/quant-lib.ts +80 -0
  250. package/src/lib/reportos.ts +175 -0
  251. package/src/lib/research-os.ts +306 -0
  252. package/src/lib/resource-estimator.ts +114 -0
  253. package/src/lib/rpm-governor.ts +93 -0
  254. package/src/lib/runtime-estimator.ts +135 -0
  255. package/src/lib/sage/empty-space-v6.ts +560 -0
  256. package/src/lib/sage/empty-space-v7.ts +222 -0
  257. package/src/lib/sage/empty-space.ts +733 -0
  258. package/src/lib/sage/engine.ts +786 -0
  259. package/src/lib/sage/index.ts +17 -0
  260. package/src/lib/sage/judge.ts +246 -0
  261. package/src/lib/sage/prng.ts +53 -0
  262. package/src/lib/sage/reality-grounding.ts +380 -0
  263. package/src/lib/sage/repetition.ts +151 -0
  264. package/src/lib/sage/saga-os-v2-engines.ts +1870 -0
  265. package/src/lib/sage/saga-os-v2.ts +274 -0
  266. package/src/lib/sage/saga-os-v3-core.ts +1491 -0
  267. package/src/lib/sage/saga-os-v3-release.ts +739 -0
  268. package/src/lib/sage/saga-os-v4-aureate.ts +1161 -0
  269. package/src/lib/sage/saga-os-v4.ts +212 -0
  270. package/src/lib/sage/saga-os-v5.ts +205 -0
  271. package/src/lib/sage/saga-os-v6.ts +346 -0
  272. package/src/lib/sage/saga-os-v7.ts +314 -0
  273. package/src/lib/sage/saga-os-v8.ts +505 -0
  274. package/src/lib/sage/saga-os.ts +329 -0
  275. package/src/lib/sage/taxonomy.ts +403 -0
  276. package/src/lib/sage/unified-roll.ts +524 -0
  277. package/src/lib/sage/worked-sketches.ts +44 -0
  278. package/src/lib/sage.ts +166 -0
  279. package/src/lib/scraper-debug-bus.ts +53 -0
  280. package/src/lib/scraper-enhanced.orig.ts +153 -0
  281. package/src/lib/scraper-enhanced.ts +10 -0
  282. package/src/lib/scraper-hardener.base.orig.ts +155 -0
  283. package/src/lib/scraper-hardener.base.ts +317 -0
  284. package/src/lib/scraper-hardener.ts +1 -0
  285. package/src/lib/scraper-palisade/palisade-adjudicator.orig.ts +419 -0
  286. package/src/lib/scraper-palisade/palisade-adjudicator.ts +13 -0
  287. package/src/lib/scraper-vnext/arbiter-omega.orig.ts +688 -0
  288. package/src/lib/scraper-vnext/arbiter-omega.ts +13 -0
  289. package/src/lib/scraper-vnext/canonical-portfolio-augments.ts +479 -0
  290. package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.orig.ts +1529 -0
  291. package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.ts +13 -0
  292. package/src/lib/scraper-vnext/conclave-omega.ts +1830 -0
  293. package/src/lib/scraper-vnext/content-extractor-v2.ts +226 -0
  294. package/src/lib/scraper-vnext/diagnostics-suite.ts +36 -0
  295. package/src/lib/scraper-vnext/epistemic-packer.ts +97 -0
  296. package/src/lib/scraper-vnext/fusion-v2.ts +65 -0
  297. package/src/lib/scraper-vnext/hydra-reader.orig.ts +1216 -0
  298. package/src/lib/scraper-vnext/hydra-reader.ts +13 -0
  299. package/src/lib/scraper-vnext/native-scraper-browser-vnext.orig.ts +91 -0
  300. package/src/lib/scraper-vnext/native-scraper-browser-vnext.ts +13 -0
  301. package/src/lib/scraper-vnext/nexus-consensus.orig.ts +905 -0
  302. package/src/lib/scraper-vnext/nexus-consensus.ts +13 -0
  303. package/src/lib/scraper-vnext/portfolio-consensus-adjudicator.ts +804 -0
  304. package/src/lib/scraper-vnext/portfolio-consensus-memory.ts +377 -0
  305. package/src/lib/scraper-vnext/portfolio-terminal-governor.ts +548 -0
  306. package/src/lib/scraper-vnext/query-strategist.orig.ts +224 -0
  307. package/src/lib/scraper-vnext/query-strategist.ts +423 -0
  308. package/src/lib/scraper-vnext/retrieval-accelerator.ts +708 -0
  309. package/src/lib/scraper-vnext/retrieval-audit-augments.ts +477 -0
  310. package/src/lib/scraper-vnext/retrieval-control-plane.ts +904 -0
  311. package/src/lib/scraper-vnext/retrieval-policy-augments.ts +358 -0
  312. package/src/lib/scraper-vnext/safe-fetch-v2.ts +157 -0
  313. package/src/lib/scraper-vnext/sentinel-omega.ts +56 -0
  314. package/src/lib/scraper-vnext/sentinel-orchestrator.ts +69 -0
  315. package/src/lib/scraper-vnext/sibyl-oracle.orig.ts +413 -0
  316. package/src/lib/scraper-vnext/sibyl-oracle.ts +13 -0
  317. package/src/lib/scraper-vnext/smart-read-v2.ts +55 -0
  318. package/src/lib/scraper-vnext/spa-rescue-bridge.ts +608 -0
  319. package/src/lib/scraper-vnext/strata-engine.orig.ts +2666 -0
  320. package/src/lib/scraper-vnext/strata-engine.ts +13 -0
  321. package/src/lib/scraper-vnext/structured-source-adapter.orig.ts +369 -0
  322. package/src/lib/scraper-vnext/structured-source-adapter.ts +34 -0
  323. package/src/lib/scraper-vnext/terminal-complete.ts +224 -0
  324. package/src/lib/scraper-vnext/terminal-final.ts +277 -0
  325. package/src/lib/scraper-vnext/terminal-saturation.ts +345 -0
  326. package/src/lib/scraper-vnext/terminal-wire.ts +425 -0
  327. package/src/lib/scraper-vnext/vanguard-titanium.orig.ts +467 -0
  328. package/src/lib/scraper-vnext/vanguard-titanium.ts +17 -0
  329. package/src/lib/search-cache.ts +138 -0
  330. package/src/lib/sloop-runner.base.ts +223 -0
  331. package/src/lib/sloop-runner.ts +104 -0
  332. package/src/lib/sloop.ts +114 -0
  333. package/src/lib/small-model-adapters.ts +82 -0
  334. package/src/lib/sscp.ts +86 -0
  335. package/src/lib/system-map.ts +54 -0
  336. package/src/lib/uni-node.ts +86 -0
  337. package/src/lib/universal-rigor-guard.ts +433 -0
  338. package/src/lib/v15-gate-testbed.ts +274 -0
  339. package/src/lib/v15-gemini.base.ts +89 -0
  340. package/src/lib/v15-gemini.ts +1 -0
  341. package/src/lib/v15-grounding.orig.ts +241 -0
  342. package/src/lib/v15-grounding.ts +79 -0
  343. package/src/lib/v15-pipeline.base.ts +769 -0
  344. package/src/lib/v15-pipeline.orig.ts +1154 -0
  345. package/src/lib/v15-pipeline.ts +674 -0
  346. package/src/lib/v15-questions.ts +64 -0
  347. package/src/lib/v15-rate-limiter.orig.ts +91 -0
  348. package/src/lib/v15-rate-limiter.ts +48 -0
  349. package/src/lib/v15-state.base.ts +87 -0
  350. package/src/lib/v15-state.ts +28 -0
  351. package/src/lib/visual-table-generator.tsx +207 -0
  352. package/src/lib/wasm-runtime.ts +133 -0
  353. package/src/lib/williams-persona-guide.ts +265 -0
  354. package/src/lib/williams-style.base.ts +464 -0
  355. package/src/lib/williams-style.ts +59 -0
  356. package/src/lib/worker-pool.ts +96 -0
  357. package/src/lib/writing-tiers.ts +125 -0
  358. package/src/main.orig.tsx +10 -0
  359. package/src/main.tsx +10 -0
  360. package/src/utils/cn.orig.ts +6 -0
  361. package/src/utils/cn.ts +6 -0
  362. package/src/vite-env.d.ts +1 -0
  363. package/tsconfig.json +31 -0
  364. package/unify.mjs +537 -0
  365. package/vite.config.ts +18 -0
@@ -0,0 +1,708 @@
1
+ /**
2
+ * retrieval-accelerator.ts
3
+ * ============================================================================
4
+ * SUBSTRATE ACCELERATOR — the retrieval-capacity layer the trust stack lacks.
5
+ *
6
+ * ADDITIVE. Zero imports from the stack. Zero file modifications. Browser-only,
7
+ * keyless, static-build compatible. Composes UNDER any existing fetcher: wrap
8
+ * a `() => Promise<T>` task in `schedule(url, task)` and it is governed by
9
+ * global + per-host concurrency, token-bucket pacing, AIMD adaptive parallelism,
10
+ * exponential backoff, and per-host circuit breaking.
11
+ * ============================================================================ */
12
+
13
+ export type Outcome = "ok" | "congestion" | "error" | "abort";
14
+
15
+ export interface SchedulerOptions {
16
+ globalConcurrency?: number;
17
+ hostConcurrencyStart?: number;
18
+ hostConcurrencyMin?: number;
19
+ hostConcurrencyMax?: number;
20
+ hostRefillPerSec?: number;
21
+ hostBurst?: number;
22
+ backoffBaseMs?: number;
23
+ backoffCapMs?: number;
24
+ circuitThreshold?: number;
25
+ circuitCooldownMs?: number;
26
+ increaseEvery?: number;
27
+ jitterFraction?: number;
28
+ }
29
+
30
+ export interface ScheduleContext {
31
+ attempt: number;
32
+ host: string;
33
+ hostLimit: number;
34
+ signal?: AbortSignal;
35
+ }
36
+
37
+ export interface BatchResult<T> {
38
+ url: string;
39
+ ok: boolean;
40
+ value?: T;
41
+ error?: string;
42
+ outcome: Outcome;
43
+ elapsedMs: number;
44
+ }
45
+
46
+ export interface SchedulerStats {
47
+ hosts: Array<{
48
+ host: string;
49
+ limit: number;
50
+ inUse: number;
51
+ backoffMs: number;
52
+ circuitOpen: boolean;
53
+ ok: number;
54
+ congestion: number;
55
+ error: number;
56
+ }>;
57
+ globalLimit: number;
58
+ globalInUse: number;
59
+ }
60
+
61
+ export class CongestionSignal extends Error {
62
+ retryAfterMs?: number;
63
+ constructor(message = "congestion", retryAfterMs?: number) {
64
+ super(message);
65
+ this.name = "CongestionSignal";
66
+ this.retryAfterMs = retryAfterMs;
67
+ }
68
+ }
69
+
70
+ // ═══════════════════════════════════════════════════════════════════════════
71
+ // GENERIC HELPERS
72
+ // ═══════════════════════════════════════════════════════════════════════════
73
+
74
+ function clamp(n: number, lo: number, hi: number): number {
75
+ if (!Number.isFinite(n)) return lo;
76
+ return Math.max(lo, Math.min(hi, n));
77
+ }
78
+
79
+ function nowMs(): number {
80
+ return typeof performance !== "undefined" ? performance.now() : Date.now();
81
+ }
82
+
83
+ function abortError(): Error {
84
+ const e = new Error("ABORTED");
85
+ e.name = "AbortError";
86
+ return e;
87
+ }
88
+
89
+ function isAbort(e: unknown): boolean {
90
+ return e instanceof Error && (e.name === "AbortError" || e.message === "ABORTED");
91
+ }
92
+
93
+ function hostOf(url: string): string {
94
+ try {
95
+ return new URL(url).hostname.toLowerCase().replace(/^www\./, "");
96
+ } catch {
97
+ return "invalid-host";
98
+ }
99
+ }
100
+
101
+ function delay(ms: number, signal?: AbortSignal): Promise<void> {
102
+ return new Promise((resolve, reject) => {
103
+ if (ms <= 0) return resolve();
104
+ if (signal?.aborted) return reject(abortError());
105
+ const t = setTimeout(() => {
106
+ cleanup();
107
+ resolve();
108
+ }, ms);
109
+ const onAbort = () => {
110
+ cleanup();
111
+ reject(abortError());
112
+ };
113
+ const cleanup = () => {
114
+ clearTimeout(t);
115
+ signal?.removeEventListener("abort", onAbort);
116
+ };
117
+ signal?.addEventListener("abort", onAbort, { once: true });
118
+ });
119
+ }
120
+
121
+ function classifyError(e: unknown): { outcome: Outcome; retryAfterMs?: number } {
122
+ if (isAbort(e)) return { outcome: "abort" };
123
+ if (e instanceof CongestionSignal) return { outcome: "congestion", retryAfterMs: e.retryAfterMs };
124
+ const msg = e instanceof Error ? e.message : String(e);
125
+ if (/\b(429|503|502|504)\b/.test(msg)) return { outcome: "congestion" };
126
+ if (/rate.?limit|too many requests|timeout|timed out|ceiling/i.test(msg)) {
127
+ return { outcome: "congestion" };
128
+ }
129
+ return { outcome: "error" };
130
+ }
131
+
132
+ // ═══════════════════════════════════════════════════════════════════════════
133
+ // DYNAMIC LIMITER
134
+ // ═══════════════════════════════════════════════════════════════════════════
135
+
136
+ class DynamicLimiter {
137
+ private inUse = 0;
138
+ private limit: number;
139
+ private waiters: Array<() => void> = [];
140
+
141
+ constructor(limit: number) {
142
+ this.limit = Math.max(1, Math.floor(limit));
143
+ }
144
+
145
+ get currentLimit(): number {
146
+ return this.limit;
147
+ }
148
+ get active(): number {
149
+ return this.inUse;
150
+ }
151
+
152
+ setLimit(n: number): void {
153
+ this.limit = Math.max(1, Math.floor(n));
154
+ this.pump();
155
+ }
156
+
157
+ async acquire(signal?: AbortSignal): Promise<void> {
158
+ if (this.inUse < this.limit) {
159
+ this.inUse += 1;
160
+ return;
161
+ }
162
+ await new Promise<void>((resolve, reject) => {
163
+ const w = () => {
164
+ signal?.removeEventListener("abort", onAbort);
165
+ resolve();
166
+ };
167
+ const onAbort = () => {
168
+ const idx = this.waiters.indexOf(w);
169
+ if (idx >= 0) this.waiters.splice(idx, 1);
170
+ reject(abortError());
171
+ };
172
+ if (signal?.aborted) return reject(abortError());
173
+ signal?.addEventListener("abort", onAbort, { once: true });
174
+ this.waiters.push(w);
175
+ });
176
+ }
177
+
178
+ release(): void {
179
+ this.inUse = Math.max(0, this.inUse - 1);
180
+ this.pump();
181
+ }
182
+
183
+ private pump(): void {
184
+ while (this.inUse < this.limit && this.waiters.length > 0) {
185
+ this.inUse += 1;
186
+ const w = this.waiters.shift()!;
187
+ w();
188
+ }
189
+ }
190
+ }
191
+
192
+ // ═══════════════════════════════════════════════════════════════════════════
193
+ // TOKEN BUCKET
194
+ // ═══════════════════════════════════════════════════════════════════════════
195
+
196
+ class TokenBucket {
197
+ private tokens: number;
198
+ private lastRefill: number;
199
+
200
+ constructor(
201
+ private capacity: number,
202
+ private refillPerSec: number,
203
+ ) {
204
+ this.tokens = capacity;
205
+ this.lastRefill = Date.now();
206
+ }
207
+
208
+ private refill(): void {
209
+ const now = Date.now();
210
+ const elapsedSec = (now - this.lastRefill) / 1000;
211
+ if (elapsedSec > 0) {
212
+ this.tokens = Math.min(this.capacity, this.tokens + elapsedSec * this.refillPerSec);
213
+ this.lastRefill = now;
214
+ }
215
+ }
216
+
217
+ tryTake(): boolean {
218
+ this.refill();
219
+ if (this.tokens >= 1) {
220
+ this.tokens -= 1;
221
+ return true;
222
+ }
223
+ return false;
224
+ }
225
+
226
+ msUntilNext(): number {
227
+ this.refill();
228
+ if (this.tokens >= 1) return 0;
229
+ return Math.ceil(((1 - this.tokens) / this.refillPerSec) * 1000);
230
+ }
231
+ }
232
+
233
+ // ═══════════════════════════════════════════════════════════════════════════
234
+ // HOST GOVERNOR
235
+ // ═══════════════════════════════════════════════════════════════════════════
236
+
237
+ interface GovernorConfig {
238
+ min: number;
239
+ max: number;
240
+ start: number;
241
+ refillPerSec: number;
242
+ burst: number;
243
+ backoffBaseMs: number;
244
+ backoffCapMs: number;
245
+ circuitThreshold: number;
246
+ circuitCooldownMs: number;
247
+ increaseEvery: number;
248
+ jitterFraction: number;
249
+ }
250
+
251
+ class HostGovernor {
252
+ private limiter: DynamicLimiter;
253
+ private bucket: TokenBucket;
254
+ private backoffMs = 0;
255
+ private nextAllowedAt = 0;
256
+ private circuitOpenUntil = 0;
257
+ private successStreak = 0;
258
+ private hardFailStreak = 0;
259
+
260
+ okCount = 0;
261
+ congestionCount = 0;
262
+ errorCount = 0;
263
+
264
+ constructor(
265
+ readonly host: string,
266
+ private cfg: GovernorConfig,
267
+ ) {
268
+ this.limiter = new DynamicLimiter(cfg.start);
269
+ this.bucket = new TokenBucket(cfg.burst, cfg.refillPerSec);
270
+ }
271
+
272
+ private jitter(ms: number): number {
273
+ if (ms <= 0) return 0;
274
+ const f = this.cfg.jitterFraction;
275
+ const delta = (Math.random() * 2 - 1) * f;
276
+ return Math.max(0, Math.round(ms * (1 + delta)));
277
+ }
278
+
279
+ async pace(signal?: AbortSignal): Promise<void> {
280
+ for (let guard = 0; guard < 64; guard++) {
281
+ if (signal?.aborted) throw abortError();
282
+ const now = Date.now();
283
+
284
+ if (this.circuitOpenUntil > now) {
285
+ await delay(this.circuitOpenUntil - now, signal);
286
+ continue;
287
+ }
288
+ if (this.nextAllowedAt > now) {
289
+ await delay(this.jitter(this.nextAllowedAt - now), signal);
290
+ continue;
291
+ }
292
+ if (!this.bucket.tryTake()) {
293
+ await delay(this.jitter(this.bucket.msUntilNext()), signal);
294
+ continue;
295
+ }
296
+ return;
297
+ }
298
+ }
299
+
300
+ async enter(signal?: AbortSignal): Promise<() => void> {
301
+ await this.limiter.acquire(signal);
302
+ let released = false;
303
+ return () => {
304
+ if (released) return;
305
+ released = true;
306
+ this.limiter.release();
307
+ };
308
+ }
309
+
310
+ get limit(): number {
311
+ return this.limiter.currentLimit;
312
+ }
313
+ get inUse(): number {
314
+ return this.limiter.active;
315
+ }
316
+ get currentBackoffMs(): number {
317
+ return this.backoffMs;
318
+ }
319
+ get circuitOpen(): boolean {
320
+ return this.circuitOpenUntil > Date.now();
321
+ }
322
+
323
+ record(outcome: Outcome, retryAfterMs?: number): void {
324
+ const now = Date.now();
325
+ if (outcome === "ok") {
326
+ this.okCount += 1;
327
+ this.hardFailStreak = 0;
328
+ this.successStreak += 1;
329
+ this.backoffMs = Math.floor(this.backoffMs / 2);
330
+ if (this.backoffMs < this.cfg.backoffBaseMs) this.backoffMs = 0;
331
+ this.circuitOpenUntil = 0;
332
+ if (this.successStreak >= this.cfg.increaseEvery) {
333
+ this.successStreak = 0;
334
+ this.limiter.setLimit(clamp(this.limit + 1, this.cfg.min, this.cfg.max));
335
+ }
336
+ } else if (outcome === "congestion") {
337
+ this.congestionCount += 1;
338
+ this.successStreak = 0;
339
+ this.hardFailStreak = 0;
340
+ this.limiter.setLimit(clamp(Math.floor(this.limit / 2), this.cfg.min, this.cfg.max));
341
+ const base = this.backoffMs > 0 ? this.backoffMs * 2 : this.cfg.backoffBaseMs;
342
+ this.backoffMs = clamp(Math.max(base, retryAfterMs ?? 0), this.cfg.backoffBaseMs, this.cfg.backoffCapMs);
343
+ this.nextAllowedAt = now + this.backoffMs;
344
+ } else if (outcome === "error") {
345
+ this.errorCount += 1;
346
+ this.successStreak = 0;
347
+ this.hardFailStreak += 1;
348
+ if (this.hardFailStreak >= this.cfg.circuitThreshold) {
349
+ this.circuitOpenUntil = now + this.cfg.circuitCooldownMs;
350
+ this.hardFailStreak = 0;
351
+ this.limiter.setLimit(this.cfg.min);
352
+ }
353
+ }
354
+ }
355
+ }
356
+
357
+ // ═══════════════════════════════════════════════════════════════════════════
358
+ // IN-FLIGHT COALESCER
359
+ // ═══════════════════════════════════════════════════════════════════════════
360
+
361
+ class InFlightCoalescer {
362
+ private inflight = new Map<string, Promise<unknown>>();
363
+
364
+ run<T>(key: string, factory: () => Promise<T>): Promise<T> {
365
+ const existing = this.inflight.get(key);
366
+ if (existing) return existing as Promise<T>;
367
+ const p = factory().finally(() => {
368
+ if (this.inflight.get(key) === p) this.inflight.delete(key);
369
+ });
370
+ this.inflight.set(key, p);
371
+ return p;
372
+ }
373
+ }
374
+
375
+ // ═══════════════════════════════════════════════════════════════════════════
376
+ // TTL FRESH-SERVE CACHE
377
+ // ═══════════════════════════════════════════════════════════════════════════
378
+
379
+ interface CacheEntry<T> {
380
+ key: string;
381
+ value: T;
382
+ storedAt: number;
383
+ expiresAt: number;
384
+ etag?: string;
385
+ }
386
+
387
+ const TTL_DB = "retrieval-accel-cache";
388
+ const TTL_STORE = "entries";
389
+ const TTL_VERSION = 1;
390
+ let ttlDbPromise: Promise<IDBDatabase | null> | null = null;
391
+
392
+ function ttlOpen(): Promise<IDBDatabase | null> {
393
+ if (ttlDbPromise) return ttlDbPromise;
394
+ ttlDbPromise = new Promise((resolve) => {
395
+ try {
396
+ if (typeof indexedDB === "undefined") return resolve(null);
397
+ const req = indexedDB.open(TTL_DB, TTL_VERSION);
398
+ req.onupgradeneeded = () => {
399
+ const db = req.result;
400
+ if (!db.objectStoreNames.contains(TTL_STORE)) {
401
+ db.createObjectStore(TTL_STORE, { keyPath: "key" });
402
+ }
403
+ };
404
+ req.onsuccess = () => resolve(req.result);
405
+ req.onerror = () => resolve(null);
406
+ req.onblocked = () => resolve(null);
407
+ } catch {
408
+ resolve(null);
409
+ }
410
+ });
411
+ return ttlDbPromise;
412
+ }
413
+
414
+ async function ttlGet<T>(key: string): Promise<CacheEntry<T> | null> {
415
+ const db = await ttlOpen();
416
+ if (!db) return null;
417
+ return new Promise((resolve) => {
418
+ try {
419
+ const req = db.transaction(TTL_STORE, "readonly").objectStore(TTL_STORE).get(key);
420
+ req.onsuccess = () => {
421
+ const e = req.result as CacheEntry<T> | undefined;
422
+ if (!e || e.expiresAt < Date.now()) return resolve(null);
423
+ resolve(e);
424
+ };
425
+ req.onerror = () => resolve(null);
426
+ } catch {
427
+ resolve(null);
428
+ }
429
+ });
430
+ }
431
+
432
+ async function ttlPut<T>(entry: CacheEntry<T>): Promise<void> {
433
+ const db = await ttlOpen();
434
+ if (!db) return;
435
+ await new Promise<void>((resolve) => {
436
+ try {
437
+ const req = db.transaction(TTL_STORE, "readwrite").objectStore(TTL_STORE).put(entry);
438
+ req.onsuccess = () => resolve();
439
+ req.onerror = () => resolve();
440
+ } catch {
441
+ resolve();
442
+ }
443
+ });
444
+ }
445
+
446
+ export async function cachedValue<T>(
447
+ key: string,
448
+ ttlMs: number,
449
+ factory: () => Promise<T>,
450
+ ): Promise<{ value: T; cached: boolean }> {
451
+ if (ttlMs > 0) {
452
+ const hit = await ttlGet<T>(key);
453
+ if (hit) return { value: hit.value, cached: true };
454
+ }
455
+ const value = await factory();
456
+ if (ttlMs > 0) {
457
+ await ttlPut<T>({ key, value, storedAt: Date.now(), expiresAt: Date.now() + ttlMs }).catch(() => {});
458
+ }
459
+ return { value, cached: false };
460
+ }
461
+
462
+ // ═══════════════════════════════════════════════════════════════════════════
463
+ // PRECONNECT WARMUP
464
+ // ═══════════════════════════════════════════════════════════════════════════
465
+
466
+ const warmedHosts = new Set<string>();
467
+
468
+ export function warmupHosts(urls: string[], cap = 8): void {
469
+ if (typeof document === "undefined" || !document.head) return;
470
+ const hosts: string[] = [];
471
+ const seen = new Set<string>();
472
+ for (const u of urls) {
473
+ let origin = "";
474
+ try {
475
+ origin = new URL(u).origin;
476
+ } catch {
477
+ continue;
478
+ }
479
+ if (!origin || seen.has(origin) || warmedHosts.has(origin)) continue;
480
+ seen.add(origin);
481
+ hosts.push(origin);
482
+ if (hosts.length >= cap) break;
483
+ }
484
+ for (const origin of hosts) {
485
+ try {
486
+ const link = document.createElement("link");
487
+ link.rel = "preconnect";
488
+ link.href = origin;
489
+ link.crossOrigin = "anonymous";
490
+ document.head.appendChild(link);
491
+ warmedHosts.add(origin);
492
+ } catch {
493
+ /* ignore */
494
+ }
495
+ }
496
+ }
497
+
498
+ // ═══════════════════════════════════════════════════════════════════════════
499
+ // RETRIEVAL SCHEDULER
500
+ // ═══════════════════════════════════════════════════════════════════════════
501
+
502
+ export class RetrievalScheduler {
503
+ private global: DynamicLimiter;
504
+ private governors = new Map<string, HostGovernor>();
505
+ private coalescer = new InFlightCoalescer();
506
+ private govCfg: GovernorConfig;
507
+
508
+ constructor(opts?: SchedulerOptions) {
509
+ this.global = new DynamicLimiter(clamp(opts?.globalConcurrency ?? 12, 1, 128));
510
+ this.govCfg = {
511
+ min: clamp(opts?.hostConcurrencyMin ?? 1, 1, 32),
512
+ max: clamp(opts?.hostConcurrencyMax ?? 6, 1, 32),
513
+ start: clamp(opts?.hostConcurrencyStart ?? 2, 1, 32),
514
+ refillPerSec: clamp(opts?.hostRefillPerSec ?? 4, 0.2, 100),
515
+ burst: clamp(opts?.hostBurst ?? 6, 1, 100),
516
+ backoffBaseMs: clamp(opts?.backoffBaseMs ?? 500, 50, 60_000),
517
+ backoffCapMs: clamp(opts?.backoffCapMs ?? 30_000, 500, 300_000),
518
+ circuitThreshold: clamp(opts?.circuitThreshold ?? 4, 1, 50),
519
+ circuitCooldownMs: clamp(opts?.circuitCooldownMs ?? 20_000, 1_000, 600_000),
520
+ increaseEvery: clamp(opts?.increaseEvery ?? 3, 1, 50),
521
+ jitterFraction: clamp(opts?.jitterFraction ?? 0.25, 0, 1),
522
+ };
523
+ this.govCfg.start = clamp(this.govCfg.start, this.govCfg.min, this.govCfg.max);
524
+ }
525
+
526
+ private governor(host: string): HostGovernor {
527
+ let g = this.governors.get(host);
528
+ if (!g) {
529
+ g = new HostGovernor(host, this.govCfg);
530
+ this.governors.set(host, g);
531
+ }
532
+ return g;
533
+ }
534
+
535
+ async schedule<T>(
536
+ url: string,
537
+ task: (ctx: ScheduleContext) => Promise<T>,
538
+ signal?: AbortSignal,
539
+ ): Promise<T> {
540
+ const host = hostOf(url);
541
+ const gov = this.governor(host);
542
+
543
+ await gov.pace(signal);
544
+ await this.global.acquire(signal);
545
+ const releaseHost = await gov.enter(signal).catch((e) => {
546
+ this.global.release();
547
+ throw e;
548
+ });
549
+
550
+ try {
551
+ return await task({ attempt: 1, host, hostLimit: gov.limit, signal });
552
+ } catch (e) {
553
+ const { outcome, retryAfterMs } = classifyError(e);
554
+ gov.record(outcome, retryAfterMs);
555
+ throw e;
556
+ } finally {
557
+ releaseHost();
558
+ this.global.release();
559
+ }
560
+ }
561
+
562
+ scheduleCoalesced<T>(
563
+ url: string,
564
+ task: (ctx: ScheduleContext) => Promise<T>,
565
+ signal?: AbortSignal,
566
+ ): Promise<T> {
567
+ const key = `${hostOf(url)}\u0000${url}`;
568
+ return this.coalescer.run(key, () => this.schedule(url, task, signal));
569
+ }
570
+
571
+ async scrapeMany<T>(
572
+ urls: string[],
573
+ worker: (url: string, ctx: ScheduleContext) => Promise<T>,
574
+ opts?: {
575
+ signal?: AbortSignal;
576
+ cacheTtlMs?: number;
577
+ coalesce?: boolean;
578
+ warmup?: boolean;
579
+ onProgress?: (done: number, total: number, last: BatchResult<T>) => void;
580
+ },
581
+ ): Promise<BatchResult<T>[]> {
582
+ const clean = urls.filter((u) => typeof u === "string" && u.trim().length > 0);
583
+ if (clean.length === 0) return [];
584
+
585
+ if (opts?.warmup !== false) warmupHosts(clean);
586
+
587
+ const total = clean.length;
588
+ let done = 0;
589
+ const cacheTtl = Math.max(0, opts?.cacheTtlMs ?? 0);
590
+
591
+ const runOne = async (url: string): Promise<BatchResult<T>> => {
592
+ const start = nowMs();
593
+ const exec = (): Promise<T> => {
594
+ const call = (ctx: ScheduleContext) => worker(url, ctx);
595
+ const scheduled = () =>
596
+ opts?.coalesce
597
+ ? this.scheduleCoalesced(url, call, opts?.signal)
598
+ : this.schedule(url, call, opts?.signal);
599
+ if (cacheTtl > 0) {
600
+ return cachedValue(`read\u0000${url}`, cacheTtl, scheduled).then((r) => r.value);
601
+ }
602
+ return scheduled();
603
+ };
604
+
605
+ try {
606
+ const value = await exec();
607
+ const res: BatchResult<T> = {
608
+ url,
609
+ ok: true,
610
+ value,
611
+ outcome: "ok",
612
+ elapsedMs: Math.round(nowMs() - start),
613
+ };
614
+ done += 1;
615
+ opts?.onProgress?.(done, total, res);
616
+ return res;
617
+ } catch (e) {
618
+ const { outcome } = classifyError(e);
619
+ const res: BatchResult<T> = {
620
+ url,
621
+ ok: false,
622
+ error: e instanceof Error ? e.message : String(e),
623
+ outcome,
624
+ elapsedMs: Math.round(nowMs() - start),
625
+ };
626
+ done += 1;
627
+ opts?.onProgress?.(done, total, res);
628
+ return res;
629
+ }
630
+ };
631
+
632
+ const settled = await Promise.allSettled(clean.map(runOne));
633
+ return settled.map((s, i) =>
634
+ s.status === "fulfilled"
635
+ ? s.value
636
+ : {
637
+ url: clean[i],
638
+ ok: false,
639
+ error: s.reason instanceof Error ? s.reason.message : "rejected",
640
+ outcome: "error" as Outcome,
641
+ elapsedMs: 0,
642
+ },
643
+ );
644
+ }
645
+
646
+ stats(): SchedulerStats {
647
+ return {
648
+ globalLimit: this.global.currentLimit,
649
+ globalInUse: this.global.active,
650
+ hosts: Array.from(this.governors.values())
651
+ .map((g) => ({
652
+ host: g.host,
653
+ limit: g.limit,
654
+ inUse: g.inUse,
655
+ backoffMs: g.currentBackoffMs,
656
+ circuitOpen: g.circuitOpen,
657
+ ok: g.okCount,
658
+ congestion: g.congestionCount,
659
+ error: g.errorCount,
660
+ }))
661
+ .sort((a, b) => a.host.localeCompare(b.host)),
662
+ };
663
+ }
664
+ }
665
+
666
+ let _default: RetrievalScheduler | null = null;
667
+
668
+ export function getDefaultScheduler(opts?: SchedulerOptions): RetrievalScheduler {
669
+ if (!_default) _default = new RetrievalScheduler(opts);
670
+ return _default;
671
+ }
672
+
673
+ export function acceleratedScrapeMany<T>(
674
+ urls: string[],
675
+ worker: (url: string, ctx: ScheduleContext) => Promise<T>,
676
+ opts?: Parameters<RetrievalScheduler["scrapeMany"]>[2] & SchedulerOptions,
677
+ ): Promise<BatchResult<T>[]> {
678
+ return getDefaultScheduler(opts).scrapeMany(urls, worker, opts);
679
+ }
680
+
681
+ export async function runAcceleratorDiagnostics(): Promise<{
682
+ ok: boolean;
683
+ checks: Array<{ id: string; passed: boolean; detail: string }>;
684
+ }> {
685
+ const checks: Array<{ id: string; passed: boolean; detail: string }> = [];
686
+ const add = (id: string, passed: boolean, detail: string) =>
687
+ checks.push({ id, passed, detail });
688
+
689
+ try {
690
+ const lim = new DynamicLimiter(2);
691
+ let active = 0;
692
+ let peak = 0;
693
+ const task = async () => {
694
+ await lim.acquire();
695
+ active += 1;
696
+ peak = Math.max(peak, active);
697
+ await delay(5);
698
+ active -= 1;
699
+ lim.release();
700
+ };
701
+ await Promise.all(Array.from({ length: 8 }, task));
702
+ add("limiter-bounds-concurrency", peak <= 2, `peak=${peak}`);
703
+ } catch (e) {
704
+ add("limiter-bounds-concurrency", false, e instanceof Error ? e.message : String(e));
705
+ }
706
+
707
+ return { ok: checks.every((c) => c.passed), checks };
708
+ }