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.
- package/diagnostics.mjs +141 -0
- package/dist/compute.worker-j5ahIpF-.js +1 -0
- package/dist/graph.worker-DG6iGCB9.js +1 -0
- package/dist/index.html +2314 -0
- package/flatten-guide.md +248 -0
- package/index.html +12 -0
- package/package.json +38 -0
- package/src/App.orig.tsx +204 -0
- package/src/App.orig1.tsx +27 -0
- package/src/App.orig2.tsx +25 -0
- package/src/App.tsx +3 -0
- package/src/BaseApp.tsx +18 -0
- package/src/INTEGRATION_LEDGER.md +22 -0
- package/src/PERSIST_CANARY.orig.txt +1 -0
- package/src/PERSIST_CANARY.txt +1 -0
- package/src/REGRESSION_LEDGER.md +651 -0
- package/src/TEMPLATE_PIPELINE_AUDIT.md +208 -0
- package/src/WILLIAMS_PERSONA_GUIDE.md +62 -0
- package/src/chat/VeritasChat.tsx +69 -0
- package/src/chat/synthesis.ts +31 -0
- package/src/chat/tier.ts +45 -0
- package/src/components/AdaptersPage.orig.tsx +99 -0
- package/src/components/AdaptersPage.tsx +3 -0
- package/src/components/AdversarialPanel.tsx +136 -0
- package/src/components/AnchorBaselinePanel.tsx +75 -0
- package/src/components/AnswerPanel.tsx +60 -0
- package/src/components/ArtifactPanel.tsx +43 -0
- package/src/components/ChatApp.orig.tsx +1582 -0
- package/src/components/ChatApp.orig1.tsx +722 -0
- package/src/components/ChatApp.tsx +95 -0
- package/src/components/ChatAugmentPanels.tsx +73 -0
- package/src/components/CitationLedgerPanel.tsx +313 -0
- package/src/components/ComputeSandboxPanel.tsx +130 -0
- package/src/components/ConfigPanel.tsx +110 -0
- package/src/components/ControlPlanePage.tsx +195 -0
- package/src/components/CreativeTreeLifePage.tsx +234 -0
- package/src/components/CreativeTreeOfLifePanel.tsx +149 -0
- package/src/components/DebugTracePanel.tsx +137 -0
- package/src/components/DeepReasoningTrace.tsx +48 -0
- package/src/components/EntitySheetPanel.tsx +51 -0
- package/src/components/FailureModesPanel.tsx +104 -0
- package/src/components/GBSDashboard.tsx +239 -0
- package/src/components/GraphView.tsx +116 -0
- package/src/components/HUD.tsx +125 -0
- package/src/components/HypothesisPanel.tsx +67 -0
- package/src/components/InnovationGenomeEngine.tsx +792 -0
- package/src/components/InnovationPersonaGuide.tsx +348 -0
- package/src/components/InnovationPersonaPanel.tsx +289 -0
- package/src/components/LiveResourceHUD.tsx +109 -0
- package/src/components/LongWriterPanel.tsx +112 -0
- package/src/components/MainPipelineV10Bridge.tsx +72 -0
- package/src/components/MarkdownLite.tsx +63 -0
- package/src/components/MemoryInspector.tsx +38 -0
- package/src/components/MemoryMonitor.tsx +52 -0
- package/src/components/MemoryStressPanel.tsx +176 -0
- package/src/components/ModulesPage.tsx +171 -0
- package/src/components/PipelineDebugConsole.orig.tsx +1856 -0
- package/src/components/PipelineDebugConsole.tsx +3 -0
- package/src/components/PreFlightHUD.tsx +67 -0
- package/src/components/PrismaFetchTracePanel.tsx +87 -0
- package/src/components/ReportOSPanel.tsx +165 -0
- package/src/components/ResourceEstimatorPage.tsx +327 -0
- package/src/components/RichText.tsx +181 -0
- package/src/components/SagaOsPanel.tsx +605 -0
- package/src/components/SagaOsReference.tsx +421 -0
- package/src/components/SagaOsV2Panel.tsx +594 -0
- package/src/components/SagaStyleTab.tsx +382 -0
- package/src/components/SageBlueprintPanel.tsx +416 -0
- package/src/components/SharedChatInput.tsx +77 -0
- package/src/components/StatFinancePanel.tsx +190 -0
- package/src/components/StylePersonaPanel.tsx +128 -0
- package/src/components/TemplatesPage.tsx +300 -0
- package/src/components/TestPanel.tsx +63 -0
- package/src/components/TraceLog.tsx +89 -0
- package/src/components/V15CalibrationAugment.tsx +1134 -0
- package/src/components/V15CalibrationDialog.tsx +1871 -0
- package/src/components/V15Overlay.orig.tsx +120 -0
- package/src/components/V15Overlay.tsx +4 -0
- package/src/components/V15OverlayWrapper.tsx +362 -0
- package/src/components/V15Toggle.tsx +34 -0
- package/src/console/DiagnosticRecoveryPanel.tsx +358 -0
- package/src/console/EngineeringConsole.tsx +103 -0
- package/src/console/FictionSystemPanels.tsx +882 -0
- package/src/console/InspectorPanels.tsx +254 -0
- package/src/console/ManuscriptGraderPanel.tsx +182 -0
- package/src/console/RecursiveReviserPanel.tsx +245 -0
- package/src/console/SeedControlPanel.tsx +135 -0
- package/src/console/StoryControllerPanel.tsx +443 -0
- package/src/console/engineBridge.ts +258 -0
- package/src/console/gemini.ts +106 -0
- package/src/console/grading.ts +250 -0
- package/src/console/util.ts +45 -0
- package/src/fiction/continuity.ts +372 -0
- package/src/fiction/crash-protection.ts +111 -0
- package/src/fiction/diagnostics.ts +208 -0
- package/src/fiction/diff.ts +74 -0
- package/src/fiction/entity-state-machine.ts +214 -0
- package/src/fiction/nive-engine.ts +404 -0
- package/src/fiction/pipeline-selftest.ts +132 -0
- package/src/fiction/seed-control.ts +193 -0
- package/src/fiction/story-engine.ts +326 -0
- package/src/fiction/types.ts +68 -0
- package/src/flatten-guide.md +379 -0
- package/src/index.css +14 -0
- package/src/index.orig.css +13 -0
- package/src/lib/academic-sources.base.ts +188 -0
- package/src/lib/academic-sources.orig.ts +28 -0
- package/src/lib/academic-sources.ts +10 -0
- package/src/lib/advanced-math.ts +119 -0
- package/src/lib/adversarial-engine.base.ts +409 -0
- package/src/lib/adversarial-engine.ts +82 -0
- package/src/lib/ai-revision.ts +623 -0
- package/src/lib/app-state.tsx +426 -0
- package/src/lib/artifact-registry.ts +97 -0
- package/src/lib/artifacts.ts +180 -0
- package/src/lib/atlas-dr.ts +167 -0
- package/src/lib/browser-mtls.ts +127 -0
- package/src/lib/browser-queue.ts +221 -0
- package/src/lib/browser-search-scraper.base.ts +382 -0
- package/src/lib/browser-search-scraper.orig.ts +90 -0
- package/src/lib/browser-search-scraper.ts +10 -0
- package/src/lib/calc-interceptor.ts +82 -0
- package/src/lib/citation-lane-tap.ts +78 -0
- package/src/lib/citation-ledger-store.ts +369 -0
- package/src/lib/citation-ledger.ts +203 -0
- package/src/lib/compute-sandbox.ts +215 -0
- package/src/lib/compute.worker.ts +153 -0
- package/src/lib/connectors/gemini.ts +120 -0
- package/src/lib/connectors/jina.ts +233 -0
- package/src/lib/connectors/marketdata.ts +51 -0
- package/src/lib/connectors/prismafetch.base.ts +175 -0
- package/src/lib/connectors/prismafetch.ts +1 -0
- package/src/lib/connectors/serpapi.ts +65 -0
- package/src/lib/connectors/wikidata.ts +44 -0
- package/src/lib/constraints.ts +331 -0
- package/src/lib/continuation-detector.base.ts +153 -0
- package/src/lib/continuation-detector.ts +48 -0
- package/src/lib/contradraft.ts +168 -0
- package/src/lib/cors-proxy.ts +120 -0
- package/src/lib/coverage.ts +81 -0
- package/src/lib/debug/architecture-prescription.ts +556 -0
- package/src/lib/debug/covea-repair.ts +543 -0
- package/src/lib/debug/helios-ground.ts +319 -0
- package/src/lib/debug/intent-decomposer.ts +281 -0
- package/src/lib/debug/intent-lattice.ts +349 -0
- package/src/lib/debug/pipeline-diagnosis.ts +1149 -0
- package/src/lib/debug/pipeline-trace-bus.ts +424 -0
- package/src/lib/debug/prompt-forge.ts +678 -0
- package/src/lib/debug/repair-sites.ts +513 -0
- package/src/lib/debug/research-phase.ts +266 -0
- package/src/lib/debug/retrieval-context.ts +76 -0
- package/src/lib/debug/retrieval-hardener.ts +142 -0
- package/src/lib/debug/scraper-debug-runner.ts +576 -0
- package/src/lib/debug/scraper-forensics.ts +418 -0
- package/src/lib/debug/scraper-lane-roadmap.ts +136 -0
- package/src/lib/debug/self-test.ts +415 -0
- package/src/lib/debug/step-attribution.ts +211 -0
- package/src/lib/debug/template-rubric.ts +301 -0
- package/src/lib/debug/unified-innovation.ts +126 -0
- package/src/lib/debug/veritas-hybrid-scraper.ts +335 -0
- package/src/lib/defense-registry.ts +104 -0
- package/src/lib/defenses.ts +162 -0
- package/src/lib/deterministic-citation-ledger.ts +174 -0
- package/src/lib/elo-registry.base.ts +117 -0
- package/src/lib/elo-registry.ts +1 -0
- package/src/lib/entity-resolver.ts +291 -0
- package/src/lib/failure-modes.ts +267 -0
- package/src/lib/feature-registry.ts +69 -0
- package/src/lib/flaw-registry.ts +143 -0
- package/src/lib/flaws/_template.ts +52 -0
- package/src/lib/flaws/builtins.ts +63 -0
- package/src/lib/flaws/finance.ts +169 -0
- package/src/lib/flaws/fixers.ts +10 -0
- package/src/lib/flaws/index.ts +32 -0
- package/src/lib/flaws/legal.ts +157 -0
- package/src/lib/flaws/medical.ts +188 -0
- package/src/lib/flaws/original-defenses-pack.ts +81 -0
- package/src/lib/flaws/sample-declarative-pack.json +38 -0
- package/src/lib/flaws/selftest.ts +201 -0
- package/src/lib/flaws/software-extended.ts +125 -0
- package/src/lib/flaws/software-rn-webgl.ts +182 -0
- package/src/lib/flaws/statistics-advanced.ts +46 -0
- package/src/lib/flaws/statistics.ts +61 -0
- package/src/lib/gbse/config.ts +20 -0
- package/src/lib/gbse/engine.ts +226 -0
- package/src/lib/gbse/graph.ts +118 -0
- package/src/lib/gbse/graph.worker.ts +21 -0
- package/src/lib/gbse/tests.ts +117 -0
- package/src/lib/gbse/tiers.ts +65 -0
- package/src/lib/gbse/types.ts +94 -0
- package/src/lib/innovation-genome-engine-v2.orig.ts +1001 -0
- package/src/lib/innovation-genome-engine-v2.ts +3 -0
- package/src/lib/innovation-genome-engine.orig.ts +330 -0
- package/src/lib/innovation-genome-engine.ts +3 -0
- package/src/lib/innovation-genome-v10.orig.ts +314 -0
- package/src/lib/innovation-genome-v10.ts +2 -0
- package/src/lib/innovation-genome-v3.orig.ts +2015 -0
- package/src/lib/innovation-genome-v3.ts +2 -0
- package/src/lib/innovation-genome-v4.orig.ts +1959 -0
- package/src/lib/innovation-genome-v4.ts +2 -0
- package/src/lib/innovation-genome-v5.orig.ts +1210 -0
- package/src/lib/innovation-genome-v5.ts +2 -0
- package/src/lib/innovation-genome-v7.orig.ts +2549 -0
- package/src/lib/innovation-genome-v7.ts +2 -0
- package/src/lib/innovation-genome-v8.orig.ts +1485 -0
- package/src/lib/innovation-genome-v8.ts +2 -0
- package/src/lib/innovation-genome-v9.orig.ts +643 -0
- package/src/lib/innovation-genome-v9.ts +2 -0
- package/src/lib/jina.base.ts +293 -0
- package/src/lib/jina.ts +1 -0
- package/src/lib/live-telemetry.ts +61 -0
- package/src/lib/longwriter.ts +84 -0
- package/src/lib/manuscript-grade-v2.ts +298 -0
- package/src/lib/memory-governor.ts +173 -0
- package/src/lib/memory-stress-tests.ts +248 -0
- package/src/lib/model-intelligence.ts +48 -0
- package/src/lib/model-rotator.ts +75 -0
- package/src/lib/models.orig.ts +513 -0
- package/src/lib/models.ts +151 -0
- package/src/lib/n-deep.base.ts +592 -0
- package/src/lib/n-deep.ts +51 -0
- package/src/lib/nih-simulator.ts +56 -0
- package/src/lib/nih-vulnerability-fixes.ts +460 -0
- package/src/lib/omega-templates.base.ts +294 -0
- package/src/lib/omega-templates.ts +225 -0
- package/src/lib/omni-nexus.ts +64 -0
- package/src/lib/oracle-adapters.ts +67 -0
- package/src/lib/oracle-registry.ts +163 -0
- package/src/lib/orchestrator.ts +357 -0
- package/src/lib/output-boundary.ts +235 -0
- package/src/lib/overrides/vite-native-chaos-harness.ts +154 -0
- package/src/lib/overrides/vite-native-contract-plane.ts +245 -0
- package/src/lib/overrides/vite-native-doctor-plane.ts +208 -0
- package/src/lib/overrides/vite-native-knowledge-store.ts +267 -0
- package/src/lib/overrides/vite-native-policy-plane.ts +190 -0
- package/src/lib/overrides/vite-native-replay-plane.ts +197 -0
- package/src/lib/overrides/vite-native-runtime-plane.ts +106 -0
- package/src/lib/overrides/vite-native-scraper.ts +848 -0
- package/src/lib/overrides/vite-native-selftest-functional.ts +217 -0
- package/src/lib/overrides/vite-native-selftest.ts +183 -0
- package/src/lib/overrides/vite-native-snapshot-plane.ts +123 -0
- package/src/lib/philosophy-toolkit.ts +75 -0
- package/src/lib/pipeline.orig.ts +659 -0
- package/src/lib/pipeline.ts +42 -0
- package/src/lib/precache.ts +128 -0
- package/src/lib/py-sandbox.ts +205 -0
- package/src/lib/quality-score.ts +96 -0
- package/src/lib/quant-engine.ts +231 -0
- package/src/lib/quant-lib.ts +80 -0
- package/src/lib/reportos.ts +175 -0
- package/src/lib/research-os.ts +306 -0
- package/src/lib/resource-estimator.ts +114 -0
- package/src/lib/rpm-governor.ts +93 -0
- package/src/lib/runtime-estimator.ts +135 -0
- package/src/lib/sage/empty-space-v6.ts +560 -0
- package/src/lib/sage/empty-space-v7.ts +222 -0
- package/src/lib/sage/empty-space.ts +733 -0
- package/src/lib/sage/engine.ts +786 -0
- package/src/lib/sage/index.ts +17 -0
- package/src/lib/sage/judge.ts +246 -0
- package/src/lib/sage/prng.ts +53 -0
- package/src/lib/sage/reality-grounding.ts +380 -0
- package/src/lib/sage/repetition.ts +151 -0
- package/src/lib/sage/saga-os-v2-engines.ts +1870 -0
- package/src/lib/sage/saga-os-v2.ts +274 -0
- package/src/lib/sage/saga-os-v3-core.ts +1491 -0
- package/src/lib/sage/saga-os-v3-release.ts +739 -0
- package/src/lib/sage/saga-os-v4-aureate.ts +1161 -0
- package/src/lib/sage/saga-os-v4.ts +212 -0
- package/src/lib/sage/saga-os-v5.ts +205 -0
- package/src/lib/sage/saga-os-v6.ts +346 -0
- package/src/lib/sage/saga-os-v7.ts +314 -0
- package/src/lib/sage/saga-os-v8.ts +505 -0
- package/src/lib/sage/saga-os.ts +329 -0
- package/src/lib/sage/taxonomy.ts +403 -0
- package/src/lib/sage/unified-roll.ts +524 -0
- package/src/lib/sage/worked-sketches.ts +44 -0
- package/src/lib/sage.ts +166 -0
- package/src/lib/scraper-debug-bus.ts +53 -0
- package/src/lib/scraper-enhanced.orig.ts +153 -0
- package/src/lib/scraper-enhanced.ts +10 -0
- package/src/lib/scraper-hardener.base.orig.ts +155 -0
- package/src/lib/scraper-hardener.base.ts +317 -0
- package/src/lib/scraper-hardener.ts +1 -0
- package/src/lib/scraper-palisade/palisade-adjudicator.orig.ts +419 -0
- package/src/lib/scraper-palisade/palisade-adjudicator.ts +13 -0
- package/src/lib/scraper-vnext/arbiter-omega.orig.ts +688 -0
- package/src/lib/scraper-vnext/arbiter-omega.ts +13 -0
- package/src/lib/scraper-vnext/canonical-portfolio-augments.ts +479 -0
- package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.orig.ts +1529 -0
- package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.ts +13 -0
- package/src/lib/scraper-vnext/conclave-omega.ts +1830 -0
- package/src/lib/scraper-vnext/content-extractor-v2.ts +226 -0
- package/src/lib/scraper-vnext/diagnostics-suite.ts +36 -0
- package/src/lib/scraper-vnext/epistemic-packer.ts +97 -0
- package/src/lib/scraper-vnext/fusion-v2.ts +65 -0
- package/src/lib/scraper-vnext/hydra-reader.orig.ts +1216 -0
- package/src/lib/scraper-vnext/hydra-reader.ts +13 -0
- package/src/lib/scraper-vnext/native-scraper-browser-vnext.orig.ts +91 -0
- package/src/lib/scraper-vnext/native-scraper-browser-vnext.ts +13 -0
- package/src/lib/scraper-vnext/nexus-consensus.orig.ts +905 -0
- package/src/lib/scraper-vnext/nexus-consensus.ts +13 -0
- package/src/lib/scraper-vnext/portfolio-consensus-adjudicator.ts +804 -0
- package/src/lib/scraper-vnext/portfolio-consensus-memory.ts +377 -0
- package/src/lib/scraper-vnext/portfolio-terminal-governor.ts +548 -0
- package/src/lib/scraper-vnext/query-strategist.orig.ts +224 -0
- package/src/lib/scraper-vnext/query-strategist.ts +423 -0
- package/src/lib/scraper-vnext/retrieval-accelerator.ts +708 -0
- package/src/lib/scraper-vnext/retrieval-audit-augments.ts +477 -0
- package/src/lib/scraper-vnext/retrieval-control-plane.ts +904 -0
- package/src/lib/scraper-vnext/retrieval-policy-augments.ts +358 -0
- package/src/lib/scraper-vnext/safe-fetch-v2.ts +157 -0
- package/src/lib/scraper-vnext/sentinel-omega.ts +56 -0
- package/src/lib/scraper-vnext/sentinel-orchestrator.ts +69 -0
- package/src/lib/scraper-vnext/sibyl-oracle.orig.ts +413 -0
- package/src/lib/scraper-vnext/sibyl-oracle.ts +13 -0
- package/src/lib/scraper-vnext/smart-read-v2.ts +55 -0
- package/src/lib/scraper-vnext/spa-rescue-bridge.ts +608 -0
- package/src/lib/scraper-vnext/strata-engine.orig.ts +2666 -0
- package/src/lib/scraper-vnext/strata-engine.ts +13 -0
- package/src/lib/scraper-vnext/structured-source-adapter.orig.ts +369 -0
- package/src/lib/scraper-vnext/structured-source-adapter.ts +34 -0
- package/src/lib/scraper-vnext/terminal-complete.ts +224 -0
- package/src/lib/scraper-vnext/terminal-final.ts +277 -0
- package/src/lib/scraper-vnext/terminal-saturation.ts +345 -0
- package/src/lib/scraper-vnext/terminal-wire.ts +425 -0
- package/src/lib/scraper-vnext/vanguard-titanium.orig.ts +467 -0
- package/src/lib/scraper-vnext/vanguard-titanium.ts +17 -0
- package/src/lib/search-cache.ts +138 -0
- package/src/lib/sloop-runner.base.ts +223 -0
- package/src/lib/sloop-runner.ts +104 -0
- package/src/lib/sloop.ts +114 -0
- package/src/lib/small-model-adapters.ts +82 -0
- package/src/lib/sscp.ts +86 -0
- package/src/lib/system-map.ts +54 -0
- package/src/lib/uni-node.ts +86 -0
- package/src/lib/universal-rigor-guard.ts +433 -0
- package/src/lib/v15-gate-testbed.ts +274 -0
- package/src/lib/v15-gemini.base.ts +89 -0
- package/src/lib/v15-gemini.ts +1 -0
- package/src/lib/v15-grounding.orig.ts +241 -0
- package/src/lib/v15-grounding.ts +79 -0
- package/src/lib/v15-pipeline.base.ts +769 -0
- package/src/lib/v15-pipeline.orig.ts +1154 -0
- package/src/lib/v15-pipeline.ts +674 -0
- package/src/lib/v15-questions.ts +64 -0
- package/src/lib/v15-rate-limiter.orig.ts +91 -0
- package/src/lib/v15-rate-limiter.ts +48 -0
- package/src/lib/v15-state.base.ts +87 -0
- package/src/lib/v15-state.ts +28 -0
- package/src/lib/visual-table-generator.tsx +207 -0
- package/src/lib/wasm-runtime.ts +133 -0
- package/src/lib/williams-persona-guide.ts +265 -0
- package/src/lib/williams-style.base.ts +464 -0
- package/src/lib/williams-style.ts +59 -0
- package/src/lib/worker-pool.ts +96 -0
- package/src/lib/writing-tiers.ts +125 -0
- package/src/main.orig.tsx +10 -0
- package/src/main.tsx +10 -0
- package/src/utils/cn.orig.ts +6 -0
- package/src/utils/cn.ts +6 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +31 -0
- package/unify.mjs +537 -0
- package/vite.config.ts +18 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scraper-hardener.base.ts — Resilient CORS Proxy Fleet with Circuit Breaker
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* REPLACES package implementation to fix runtime errors like:
|
|
5
|
+
* jina_401, corsproxy.io_circuit_open, allorigins-raw_circuit_open,
|
|
6
|
+
* cors.x2u.in_circuit_open, codetabs signal aborted, etc.
|
|
7
|
+
*
|
|
8
|
+
* Improvements:
|
|
9
|
+
* 1. Circuit breaker per proxy: tracks failures, temporarily disables failing proxies
|
|
10
|
+
* 2. Prioritized fleet: most reliable first (direct fetch prioritized)
|
|
11
|
+
* 3. Exponential backoff for retries
|
|
12
|
+
* 4. Reduced timeouts for faster failover
|
|
13
|
+
* 5. Better error classification (distinguish 401, 429, timeout, etc.)
|
|
14
|
+
* 6. Adaptive wave size based on failure rate
|
|
15
|
+
* 7. Local cache for recently fetched URLs (avoid duplicate fetches)
|
|
16
|
+
* ============================================================================ */
|
|
17
|
+
|
|
18
|
+
export interface ProxyDef {
|
|
19
|
+
name: string;
|
|
20
|
+
build: (url: string) => string;
|
|
21
|
+
unwrap?: (body: string) => string;
|
|
22
|
+
reliability: number; // 0-1, higher = more reliable
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Enhanced fleet with reliability scores — ordered by reliability
|
|
26
|
+
export const PROXY_FLEET: ProxyDef[] = [
|
|
27
|
+
// Tier 1: Most reliable (direct or well-maintained)
|
|
28
|
+
{ name: "direct", build: (u) => u, reliability: 1.0 }, // direct fetch, not a proxy but handled specially
|
|
29
|
+
{ name: "corsproxy.io", build: (u) => `https://corsproxy.io/?url=${encodeURIComponent(u)}`, reliability: 0.85 },
|
|
30
|
+
{ name: "allorigins-raw", build: (u) => `https://api.allorigins.win/raw?url=${encodeURIComponent(u)}`, reliability: 0.8 },
|
|
31
|
+
// Tier 2: Generally reliable but occasional failures
|
|
32
|
+
{ name: "codetabs", build: (u) => `https://api.codetabs.com/v1/proxy/?quest=${encodeURIComponent(u)}`, reliability: 0.7 },
|
|
33
|
+
{ name: "corsproxy.org", build: (u) => `https://corsproxy.org/?${encodeURIComponent(u)}`, reliability: 0.65 },
|
|
34
|
+
{ name: "thingproxy", build: (u) => `https://thingproxy.freeboard.io/fetch/${u}`, reliability: 0.6 },
|
|
35
|
+
// Tier 3: Fallbacks, higher failure rate
|
|
36
|
+
{ name: "cors.eu.org", build: (u) => `https://cors.eu.org/${u}`, reliability: 0.5 },
|
|
37
|
+
{ name: "proxy.cors.sh", build: (u) => `https://proxy.cors.sh/${u}`, reliability: 0.45 },
|
|
38
|
+
{ name: "yacdn", build: (u) => `https://yacdn.org/proxy/${u}`, reliability: 0.4 },
|
|
39
|
+
{ name: "whateverorigin", build: (u) => `https://whateverorigin.org/get?url=${encodeURIComponent(u)}`, unwrap: jsonContents, reliability: 0.35 },
|
|
40
|
+
{ name: "allorigins-get", build: (u) => `https://api.allorigins.win/get?url=${encodeURIComponent(u)}`, unwrap: jsonContents, reliability: 0.35 },
|
|
41
|
+
{ name: "jsonp.afeld", build: (u) => `https://jsonp.afeld.me/?url=${encodeURIComponent(u)}`, reliability: 0.3 },
|
|
42
|
+
{ name: "cors-anywhere-hf", build: (u) => `https://cors-anywhere.herokuapp.com/${u}`, reliability: 0.25 },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
function jsonContents(body: string): string {
|
|
46
|
+
try {
|
|
47
|
+
const data = JSON.parse(body);
|
|
48
|
+
return typeof data?.contents === "string" ? data.contents : body;
|
|
49
|
+
} catch {
|
|
50
|
+
return body;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const BROWSER_HEADERS: Record<string, string> = {
|
|
55
|
+
"User-Agent":
|
|
56
|
+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
|
|
57
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,text/plain;q=0.8,*/*;q=0.5",
|
|
58
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// ── Circuit Breaker ────────────────────────────────────────────────────
|
|
62
|
+
interface CircuitState {
|
|
63
|
+
failures: number;
|
|
64
|
+
lastFailure: number;
|
|
65
|
+
openUntil: number;
|
|
66
|
+
consecutiveSuccesses: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const CIRCUIT_BREAKER = new Map<string, CircuitState>();
|
|
70
|
+
const FAILURE_THRESHOLD = 3; // open circuit after 3 failures
|
|
71
|
+
const RESET_TIMEOUT = 60_000; // try again after 60s
|
|
72
|
+
|
|
73
|
+
function getCircuit(name: string): CircuitState {
|
|
74
|
+
if (!CIRCUIT_BREAKER.has(name)) {
|
|
75
|
+
CIRCUIT_BREAKER.set(name, { failures: 0, lastFailure: 0, openUntil: 0, consecutiveSuccesses: 0 });
|
|
76
|
+
}
|
|
77
|
+
return CIRCUIT_BREAKER.get(name)!;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isCircuitOpen(name: string): boolean {
|
|
81
|
+
const state = getCircuit(name);
|
|
82
|
+
if (state.openUntil === 0) return false;
|
|
83
|
+
if (Date.now() > state.openUntil) {
|
|
84
|
+
// Half-open: allow one try
|
|
85
|
+
state.openUntil = 0;
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function recordSuccess(name: string): void {
|
|
92
|
+
const state = getCircuit(name);
|
|
93
|
+
state.failures = 0;
|
|
94
|
+
state.consecutiveSuccesses += 1;
|
|
95
|
+
state.openUntil = 0;
|
|
96
|
+
// Gradually increase reliability after successes
|
|
97
|
+
if (state.consecutiveSuccesses > 5) {
|
|
98
|
+
state.failures = Math.max(0, state.failures - 1);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function recordFailure(name: string, errorType: "timeout" | "4xx" | "5xx" | "network" | "parse"): void {
|
|
103
|
+
const state = getCircuit(name);
|
|
104
|
+
state.failures += 1;
|
|
105
|
+
state.lastFailure = Date.now();
|
|
106
|
+
state.consecutiveSuccesses = 0;
|
|
107
|
+
|
|
108
|
+
// Different error types have different penalties
|
|
109
|
+
const penalty = errorType === "4xx" ? 2 : errorType === "timeout" ? 1 : 1.5;
|
|
110
|
+
const weightedFailures = state.failures * penalty;
|
|
111
|
+
|
|
112
|
+
if (weightedFailures >= FAILURE_THRESHOLD) {
|
|
113
|
+
// Exponential backoff: longer open time for more failures
|
|
114
|
+
const backoffMs = Math.min(RESET_TIMEOUT * Math.pow(2, state.failures - FAILURE_THRESHOLD), 300_000);
|
|
115
|
+
state.openUntil = Date.now() + backoffMs;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ── Cache for recent fetches ───────────────────────────────────────────
|
|
120
|
+
const FETCH_CACHE = new Map<string, { text: string; timestamp: number; source: string }>();
|
|
121
|
+
const CACHE_TTL = 5 * 60_000; // 5 minutes
|
|
122
|
+
|
|
123
|
+
function getCached(url: string): { text: string; source: string } | null {
|
|
124
|
+
const entry = FETCH_CACHE.get(url);
|
|
125
|
+
if (!entry) return null;
|
|
126
|
+
if (Date.now() - entry.timestamp > CACHE_TTL) {
|
|
127
|
+
FETCH_CACHE.delete(url);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return { text: entry.text, source: entry.source };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function setCached(url: string, text: string, source: string): void {
|
|
134
|
+
// LRU: keep max 100 entries
|
|
135
|
+
if (FETCH_CACHE.size > 100) {
|
|
136
|
+
const oldest = Array.from(FETCH_CACHE.entries()).sort((a, b) => a[1].timestamp - b[1].timestamp)[0];
|
|
137
|
+
if (oldest) FETCH_CACHE.delete(oldest[0]);
|
|
138
|
+
}
|
|
139
|
+
FETCH_CACHE.set(url, { text, timestamp: Date.now(), source });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function timedFetch(url: string, signal: AbortSignal | undefined, headers: Record<string, string>, timeoutMs = 6_000): Promise<Response> {
|
|
143
|
+
const ctrl = new AbortController();
|
|
144
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
145
|
+
const onAbort = () => ctrl.abort();
|
|
146
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
147
|
+
try {
|
|
148
|
+
return await fetch(url, { signal: ctrl.signal, headers, redirect: "follow" });
|
|
149
|
+
} finally {
|
|
150
|
+
clearTimeout(timer);
|
|
151
|
+
signal?.removeEventListener("abort", onAbort);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function looksUsable(text: string): boolean {
|
|
156
|
+
if (!text) return false;
|
|
157
|
+
if (text.length < 80) return false;
|
|
158
|
+
if (/^\s*(error|forbidden|too many requests|rate limit|unauthorized|not found)/i.test(text) && text.length < 400) return false;
|
|
159
|
+
// Reject common proxy error pages
|
|
160
|
+
if (/<title>\s*(error|forbidden|429|401|404)/i.test(text) && text.length < 1000) return false;
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface RobustFetchResult {
|
|
165
|
+
text: string;
|
|
166
|
+
source: "direct" | "proxy" | "cache";
|
|
167
|
+
proxy?: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function tryProxy(proxy: ProxyDef, url: string, signal?: AbortSignal): Promise<RobustFetchResult> {
|
|
171
|
+
if (proxy.name === "direct") {
|
|
172
|
+
// Direct fetch special case
|
|
173
|
+
const res = await timedFetch(url, signal, BROWSER_HEADERS, 8_000);
|
|
174
|
+
if (!res.ok) {
|
|
175
|
+
if (res.status === 401) throw new Error(`${proxy.name}:401`);
|
|
176
|
+
if (res.status === 429) throw new Error(`${proxy.name}:429`);
|
|
177
|
+
throw new Error(`${proxy.name}:${res.status}`);
|
|
178
|
+
}
|
|
179
|
+
const text = await res.text();
|
|
180
|
+
if (!looksUsable(text)) throw new Error(`${proxy.name}:thin`);
|
|
181
|
+
return { text, source: "direct" };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (isCircuitOpen(proxy.name)) {
|
|
185
|
+
throw new Error(`${proxy.name}:circuit_open`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const res = await timedFetch(proxy.build(url), signal, BROWSER_HEADERS, 6_000);
|
|
190
|
+
if (!res.ok) {
|
|
191
|
+
const errType = res.status >= 500 ? "5xx" : res.status >= 400 ? "4xx" : "network";
|
|
192
|
+
recordFailure(proxy.name, errType as any);
|
|
193
|
+
if (res.status === 401) throw new Error(`${proxy.name}:401`);
|
|
194
|
+
if (res.status === 429) throw new Error(`${proxy.name}:429`);
|
|
195
|
+
throw new Error(`${proxy.name}:${res.status}`);
|
|
196
|
+
}
|
|
197
|
+
const raw = await res.text();
|
|
198
|
+
const body = proxy.unwrap ? proxy.unwrap(raw) : raw;
|
|
199
|
+
if (!looksUsable(body)) {
|
|
200
|
+
recordFailure(proxy.name, "parse");
|
|
201
|
+
throw new Error(`${proxy.name}:thin`);
|
|
202
|
+
}
|
|
203
|
+
recordSuccess(proxy.name);
|
|
204
|
+
return { text: body, source: "proxy", proxy: proxy.name };
|
|
205
|
+
} catch (e: any) {
|
|
206
|
+
const msg = e?.message || String(e);
|
|
207
|
+
if (!msg.includes("circuit_open") && !msg.includes("401") && !msg.includes("429")) {
|
|
208
|
+
const errType = msg.includes("aborted") || msg.includes("timeout") ? "timeout" : "network";
|
|
209
|
+
recordFailure(proxy.name, errType as any);
|
|
210
|
+
}
|
|
211
|
+
throw e;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function firstSuccess<T>(promises: Promise<T>[]): Promise<T> {
|
|
216
|
+
return new Promise((resolve, reject) => {
|
|
217
|
+
let remaining = promises.length;
|
|
218
|
+
const errors: any[] = [];
|
|
219
|
+
if (remaining === 0) reject(new Error("no candidates"));
|
|
220
|
+
promises.forEach(p => p.then(resolve, (e) => {
|
|
221
|
+
errors.push(e);
|
|
222
|
+
if (--remaining === 0) reject(new Error(errors.map(x => x?.message ?? x).join(", ")));
|
|
223
|
+
}));
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export async function fetchRobust(url: string, signal?: AbortSignal, preferProxy?: string): Promise<RobustFetchResult> {
|
|
228
|
+
// Check cache first
|
|
229
|
+
const cached = getCached(url);
|
|
230
|
+
if (cached) {
|
|
231
|
+
return { text: cached.text, source: "cache" as any, proxy: cached.source };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const errors: string[] = [];
|
|
235
|
+
|
|
236
|
+
// 0. Pinned proxy first if specified and not circuit-open
|
|
237
|
+
if (preferProxy) {
|
|
238
|
+
const pinned = PROXY_FLEET.find(p => p.name === preferProxy);
|
|
239
|
+
if (pinned && !isCircuitOpen(pinned.name)) {
|
|
240
|
+
try {
|
|
241
|
+
const result = await tryProxy(pinned, url, signal);
|
|
242
|
+
setCached(url, result.text, result.proxy || result.source);
|
|
243
|
+
return result;
|
|
244
|
+
} catch (e: any) {
|
|
245
|
+
errors.push(e?.message ?? "pinned-failed");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 1. Direct fetch first (most reliable for CORS-enabled origins)
|
|
251
|
+
try {
|
|
252
|
+
const directProxy = PROXY_FLEET[0]; // "direct" is first
|
|
253
|
+
const result = await tryProxy(directProxy, url, signal);
|
|
254
|
+
setCached(url, result.text, "direct");
|
|
255
|
+
return result;
|
|
256
|
+
} catch (e: any) {
|
|
257
|
+
errors.push(e?.message ?? "direct-failed");
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 2. Race the proxy fleet in adaptive waves
|
|
261
|
+
// Sort by reliability, filter out circuit-open proxies
|
|
262
|
+
const availableProxies = PROXY_FLEET.slice(1)
|
|
263
|
+
.filter(p => !isCircuitOpen(p.name))
|
|
264
|
+
.sort((a, b) => b.reliability - a.reliability);
|
|
265
|
+
|
|
266
|
+
if (availableProxies.length === 0) {
|
|
267
|
+
throw new Error(`CORS_BLOCKED: all proxies circuit-open for ${url} [${errors.join("; ").slice(0, 300)}]`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Adaptive wave size: larger waves when many proxies available, smaller when few
|
|
271
|
+
const WAVE = availableProxies.length > 6 ? 3 : 2;
|
|
272
|
+
|
|
273
|
+
for (let i = 0; i < availableProxies.length; i += WAVE) {
|
|
274
|
+
if (signal?.aborted) break;
|
|
275
|
+
const wave = availableProxies.slice(i, i + WAVE);
|
|
276
|
+
try {
|
|
277
|
+
const result = await firstSuccess(wave.map(p => tryProxy(p, url, signal)));
|
|
278
|
+
setCached(url, result.text, result.proxy || result.source);
|
|
279
|
+
return result;
|
|
280
|
+
} catch (e: any) {
|
|
281
|
+
errors.push(e?.message ?? "wave-failed");
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
throw new Error(`CORS_BLOCKED: all paths failed for ${url} [${errors.join("; ").slice(0, 300)}]`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function extractTextFromHtml(html: string): string {
|
|
289
|
+
let text = html.replace(/<(script|style|nav|footer|header|noscript|svg)[^>]*>[\s\S]*?<\/\1>/gi, "");
|
|
290
|
+
text = text.replace(/<[^>]+>/g, " ");
|
|
291
|
+
text = text
|
|
292
|
+
.replace(/ /g, " ")
|
|
293
|
+
.replace(/&/g, "&")
|
|
294
|
+
.replace(/</g, "<")
|
|
295
|
+
.replace(/>/g, ">")
|
|
296
|
+
.replace(/"/g, '"')
|
|
297
|
+
.replace(/'|'/g, "'");
|
|
298
|
+
return text.replace(/\s+/g, " ").trim().slice(0, 12_000);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ── Diagnostic helpers ──────────────────────────────────────────────────
|
|
302
|
+
export function getCircuitBreakerStatus(): Array<{ proxy: string; failures: number; open: boolean; openUntil: number }> {
|
|
303
|
+
return Array.from(CIRCUIT_BREAKER.entries()).map(([name, state]) => ({
|
|
304
|
+
proxy: name,
|
|
305
|
+
failures: state.failures,
|
|
306
|
+
open: isCircuitOpen(name),
|
|
307
|
+
openUntil: state.openUntil,
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function resetCircuitBreaker(proxyName?: string): void {
|
|
312
|
+
if (proxyName) {
|
|
313
|
+
CIRCUIT_BREAKER.delete(proxyName);
|
|
314
|
+
} else {
|
|
315
|
+
CIRCUIT_BREAKER.clear();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./scraper-hardener.base";
|