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,608 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spa-rescue-bridge.ts
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* ADDITIVE bridge that closes the one self-documented gap in the canonical
|
|
5
|
+
* stack: `structured-source-adapter.ts`'s `rescueSpaPayload()` requires the
|
|
6
|
+
* raw HTML to arrive via `Error.cause`, but `retrieval-policy-augments.ts`'s
|
|
7
|
+
* `withChallengeGate()` throws a plain `Error(message)` with no `.cause`.
|
|
8
|
+
* As documented by the canonical author: "This is a known limitation,
|
|
9
|
+
* documented, not a silent bug." This file closes it without touching either
|
|
10
|
+
* canonical file.
|
|
11
|
+
*
|
|
12
|
+
* WHAT THIS DOES:
|
|
13
|
+
* Wraps a base reader with:
|
|
14
|
+
* 1. Content classification: distinguish TRUE bot-challenges (Turnstile,
|
|
15
|
+
* CAPTCHA, WAF block pages — hard failures that must propagate so the
|
|
16
|
+
* circuit breaker in retrieval-control-plane.ts responds correctly)
|
|
17
|
+
* from SOFT SPA shells / thin-content pages (safe to rescue).
|
|
18
|
+
* 2. On a soft failure, attaches the raw HTML as `Error.cause` in the
|
|
19
|
+
* exact shape `structured-source-adapter.ts`'s `wrappedStructuredChallengeReader`
|
|
20
|
+
* already expects (a string > 200 chars), then re-throws so the
|
|
21
|
+
* existing canonical rescue logic activates unmodified.
|
|
22
|
+
* 3. On a hard failure (real challenge), re-throws with NO cause,
|
|
23
|
+
* preserving the canonical circuit-breaker/challenge-gate semantics
|
|
24
|
+
* exactly as designed — this is the safety-critical distinction.
|
|
25
|
+
*
|
|
26
|
+
* WHAT THIS EXPLICITLY DOES NOT DO (red-teamed and rejected this session):
|
|
27
|
+
* - Does NOT attempt any new transport lane, proxy, or CORS bypass.
|
|
28
|
+
* - Does NOT modify retrieval-policy-augments.ts's detectChallenge/
|
|
29
|
+
* withChallengeGate or structured-source-adapter.ts's rescue functions.
|
|
30
|
+
*
|
|
31
|
+
* ADDITIVE ONLY. Zero new npm deps. Browser-only, keyless.
|
|
32
|
+
* NOT EXECUTED in this environment.
|
|
33
|
+
* ============================================================================ */
|
|
34
|
+
|
|
35
|
+
import type { ScheduleContext, RetrievalPolicy, CrawlPayload } from "./retrieval-control-plane";
|
|
36
|
+
import { detectPageBlock } from "./retrieval-policy-augments";
|
|
37
|
+
|
|
38
|
+
// Adapter around detectPageBlock to provide standard isChallenge/isSpaShell properties
|
|
39
|
+
export function detectChallenge(html: string): {
|
|
40
|
+
isChallenge: boolean;
|
|
41
|
+
isSpaShell: boolean;
|
|
42
|
+
markers: string[];
|
|
43
|
+
} {
|
|
44
|
+
const d = detectPageBlock(html);
|
|
45
|
+
return {
|
|
46
|
+
isChallenge: d.blocked,
|
|
47
|
+
isSpaShell: d.softShell,
|
|
48
|
+
markers: d.markers,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
53
|
+
// SOFT vs HARD FAILURE CLASSIFICATION
|
|
54
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A "soft" failure is one where detectChallenge() found NO true challenge
|
|
58
|
+
* markers (Turnstile/CAPTCHA/WAF text) but the content was still rejected —
|
|
59
|
+
* i.e. it was thin, an SPA shell, or low-text-ratio. These are the ONLY
|
|
60
|
+
* cases eligible for rescue. A true isChallenge=true case is a real bot
|
|
61
|
+
* block and MUST propagate unmodified so the circuit breaker in
|
|
62
|
+
* retrieval-control-plane.ts opens correctly for that host.
|
|
63
|
+
*/
|
|
64
|
+
export function isSoftFailure(html: string): boolean {
|
|
65
|
+
const d = detectChallenge(html);
|
|
66
|
+
return !d.isChallenge && (d.isSpaShell || d.markers.length > 0);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
70
|
+
// PUBLIC API
|
|
71
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* withSpaRescueCause — wraps a base reader (the one you'd normally pass to
|
|
75
|
+
* canonical `withChallengeGate()`) so that when the underlying fetch succeeds
|
|
76
|
+
* in getting bytes but the CONTENT is a soft SPA shell / thin page (not a
|
|
77
|
+
* true bot-challenge), the raw HTML is captured and attached to the thrown
|
|
78
|
+
* error's `.cause` in the exact shape `structured-source-adapter.ts`'s
|
|
79
|
+
* `wrappedStructuredChallengeReader` already expects.
|
|
80
|
+
*/
|
|
81
|
+
export function withSpaRescueCause<T>(
|
|
82
|
+
reader: (url: string, ctx: ScheduleContext, policy: RetrievalPolicy) => Promise<CrawlPayload<T>>,
|
|
83
|
+
): (url: string, ctx: ScheduleContext, policy: RetrievalPolicy) => Promise<CrawlPayload<T>> {
|
|
84
|
+
return async (url, ctx, policy) => {
|
|
85
|
+
try {
|
|
86
|
+
const payload = await reader(url, ctx, policy);
|
|
87
|
+
return payload;
|
|
88
|
+
} catch (e) {
|
|
89
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
90
|
+
const existingCause = (err as { cause?: unknown }).cause;
|
|
91
|
+
if (typeof existingCause === "string" && existingCause.length > 200) {
|
|
92
|
+
if (isSoftFailure(existingCause)) {
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
const stripped = new Error(err.message);
|
|
96
|
+
throw stripped;
|
|
97
|
+
}
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* withSpaRescueFromRawResponse — the PRIMARY, fully-functional rescue path.
|
|
105
|
+
* Use this INSTEAD of `withChallengeGate` (not layered on top of it) when
|
|
106
|
+
* you construct your own base reader, because it has access to the raw
|
|
107
|
+
* fetched text BEFORE any challenge-gate throws away that context.
|
|
108
|
+
*/
|
|
109
|
+
export function withSpaRescueFromRawResponse<T>(
|
|
110
|
+
rawReader: (url: string, ctx: ScheduleContext, policy: RetrievalPolicy) => Promise<CrawlPayload<T>>,
|
|
111
|
+
): (url: string, ctx: ScheduleContext, policy: RetrievalPolicy) => Promise<CrawlPayload<T>> {
|
|
112
|
+
return async (url, ctx, policy) => {
|
|
113
|
+
const payload = await rawReader(url, ctx, policy);
|
|
114
|
+
const html = payload.text ?? "";
|
|
115
|
+
const classification = detectChallenge(html);
|
|
116
|
+
|
|
117
|
+
if (classification.isChallenge) {
|
|
118
|
+
throw new Error(`challenge_detected:${classification.markers[0] ?? "unknown"}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (classification.isSpaShell || html.trim().length < 80) {
|
|
122
|
+
const err = new Error(
|
|
123
|
+
classification.isSpaShell ? "spa_shell_detected" : "thin_content_detected",
|
|
124
|
+
);
|
|
125
|
+
if (html.length > 200) {
|
|
126
|
+
(err as { cause?: unknown }).cause = html;
|
|
127
|
+
}
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return payload;
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
136
|
+
// DIAGNOSTICS
|
|
137
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
138
|
+
|
|
139
|
+
export async function runSpaRescueBridgeDiagnostics(): Promise<{
|
|
140
|
+
ok: boolean;
|
|
141
|
+
checks: Array<{
|
|
142
|
+
id: string;
|
|
143
|
+
passed: boolean;
|
|
144
|
+
detail: string;
|
|
145
|
+
}>;
|
|
146
|
+
}> {
|
|
147
|
+
const checks: Array<{
|
|
148
|
+
id: string;
|
|
149
|
+
passed: boolean;
|
|
150
|
+
detail: string;
|
|
151
|
+
}> = [];
|
|
152
|
+
|
|
153
|
+
const add = (
|
|
154
|
+
id: string,
|
|
155
|
+
passed: boolean,
|
|
156
|
+
detail: string,
|
|
157
|
+
): void => {
|
|
158
|
+
checks.push({ id, passed, detail });
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const mockController = new AbortController();
|
|
162
|
+
|
|
163
|
+
const mockCtx = {
|
|
164
|
+
attempt: 1,
|
|
165
|
+
host: "example.com",
|
|
166
|
+
hostLimit: 1,
|
|
167
|
+
signal: mockController.signal,
|
|
168
|
+
} as ScheduleContext;
|
|
169
|
+
|
|
170
|
+
const mockPolicy = {
|
|
171
|
+
policyVersion: "diagnostic",
|
|
172
|
+
extractionVersion: "diagnostic",
|
|
173
|
+
maxBytes: 2_000_000,
|
|
174
|
+
freshnessMs: 0,
|
|
175
|
+
requiredLaneClasses: 1,
|
|
176
|
+
cacheMode: "off",
|
|
177
|
+
robotsMode: "off",
|
|
178
|
+
scope: "seed-origins",
|
|
179
|
+
allowHostedRenderer: true,
|
|
180
|
+
allowPublicRelays: true,
|
|
181
|
+
allowArchive: true,
|
|
182
|
+
} as RetrievalPolicy;
|
|
183
|
+
|
|
184
|
+
// 1. Clean content passes through unchanged.
|
|
185
|
+
{
|
|
186
|
+
const wrapped =
|
|
187
|
+
withSpaRescueFromRawResponse<string>(
|
|
188
|
+
async () => ({
|
|
189
|
+
value: "ok",
|
|
190
|
+
text:
|
|
191
|
+
"<article><p>" +
|
|
192
|
+
"Normal readable article content spanning several sentences. ".repeat(
|
|
193
|
+
10,
|
|
194
|
+
) +
|
|
195
|
+
"</p></article>",
|
|
196
|
+
contentType: "text/html",
|
|
197
|
+
canonicalUrl:
|
|
198
|
+
"https://example.com/article",
|
|
199
|
+
bytesRead: 640,
|
|
200
|
+
}),
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
const result = await wrapped(
|
|
205
|
+
"https://example.com/article",
|
|
206
|
+
mockCtx,
|
|
207
|
+
mockPolicy,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
add(
|
|
211
|
+
"clean-content-passes",
|
|
212
|
+
result.value === "ok",
|
|
213
|
+
`value=${String(result.value)}`,
|
|
214
|
+
);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
add(
|
|
217
|
+
"clean-content-passes",
|
|
218
|
+
false,
|
|
219
|
+
error instanceof Error
|
|
220
|
+
? error.message
|
|
221
|
+
: "unexpected rejection",
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 2. SPA shell throws with the original HTML as Error.cause.
|
|
227
|
+
{
|
|
228
|
+
const spaHtml =
|
|
229
|
+
'<html><head><meta property="og:title" content="SPA article"></head>' +
|
|
230
|
+
'<body><div id="__next"></div><script src="/app.js"></script></body></html>' +
|
|
231
|
+
"x".repeat(240);
|
|
232
|
+
|
|
233
|
+
const wrapped =
|
|
234
|
+
withSpaRescueFromRawResponse<string>(
|
|
235
|
+
async () => ({
|
|
236
|
+
value: "spa",
|
|
237
|
+
text: spaHtml,
|
|
238
|
+
contentType: "text/html",
|
|
239
|
+
canonicalUrl:
|
|
240
|
+
"https://spa.example.com/article",
|
|
241
|
+
bytesRead: spaHtml.length,
|
|
242
|
+
}),
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
await wrapped(
|
|
247
|
+
"https://spa.example.com/article",
|
|
248
|
+
mockCtx,
|
|
249
|
+
mockPolicy,
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
add(
|
|
253
|
+
"spa-shell-throws-with-cause",
|
|
254
|
+
false,
|
|
255
|
+
"did not throw",
|
|
256
|
+
);
|
|
257
|
+
} catch (error) {
|
|
258
|
+
const cause = (
|
|
259
|
+
error as { cause?: unknown }
|
|
260
|
+
).cause;
|
|
261
|
+
|
|
262
|
+
add(
|
|
263
|
+
"spa-shell-throws-with-cause",
|
|
264
|
+
typeof cause === "string" &&
|
|
265
|
+
cause === spaHtml &&
|
|
266
|
+
cause.includes("__next"),
|
|
267
|
+
`causeType=${typeof cause} causeLength=${
|
|
268
|
+
typeof cause === "string"
|
|
269
|
+
? cause.length
|
|
270
|
+
: 0
|
|
271
|
+
}`,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// 3. A genuine WAF/challenge response must not expose rescue data.
|
|
277
|
+
{
|
|
278
|
+
const challengeHtml =
|
|
279
|
+
"<html><body>" +
|
|
280
|
+
'<div class="cf-challenge">' +
|
|
281
|
+
"Checking your browser. Turnstile verification required." +
|
|
282
|
+
"</div>" +
|
|
283
|
+
"</body></html>";
|
|
284
|
+
|
|
285
|
+
const wrapped =
|
|
286
|
+
withSpaRescueFromRawResponse<string>(
|
|
287
|
+
async () => ({
|
|
288
|
+
value: "blocked",
|
|
289
|
+
text: challengeHtml,
|
|
290
|
+
contentType: "text/html",
|
|
291
|
+
canonicalUrl:
|
|
292
|
+
"https://blocked.example.com/article",
|
|
293
|
+
bytesRead: challengeHtml.length,
|
|
294
|
+
}),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
await wrapped(
|
|
299
|
+
"https://blocked.example.com/article",
|
|
300
|
+
mockCtx,
|
|
301
|
+
mockPolicy,
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
add(
|
|
305
|
+
"hard-challenge-throws-without-cause",
|
|
306
|
+
false,
|
|
307
|
+
"did not throw",
|
|
308
|
+
);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
const cause = (
|
|
311
|
+
error as { cause?: unknown }
|
|
312
|
+
).cause;
|
|
313
|
+
|
|
314
|
+
const message =
|
|
315
|
+
error instanceof Error
|
|
316
|
+
? error.message
|
|
317
|
+
: String(error);
|
|
318
|
+
|
|
319
|
+
add(
|
|
320
|
+
"hard-challenge-throws-without-cause",
|
|
321
|
+
cause === undefined &&
|
|
322
|
+
message.startsWith(
|
|
323
|
+
"challenge_detected:",
|
|
324
|
+
),
|
|
325
|
+
`causePresent=${
|
|
326
|
+
cause !== undefined
|
|
327
|
+
} message=${message}`,
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// 4. Very short content contains nothing useful to salvage.
|
|
333
|
+
{
|
|
334
|
+
const wrapped =
|
|
335
|
+
withSpaRescueFromRawResponse<string>(
|
|
336
|
+
async () => ({
|
|
337
|
+
value: "thin",
|
|
338
|
+
text: "x".repeat(50),
|
|
339
|
+
contentType: "text/html",
|
|
340
|
+
canonicalUrl:
|
|
341
|
+
"https://thin.example.com/article",
|
|
342
|
+
bytesRead: 50,
|
|
343
|
+
}),
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
await wrapped(
|
|
348
|
+
"https://thin.example.com/article",
|
|
349
|
+
mockCtx,
|
|
350
|
+
mockPolicy,
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
add(
|
|
354
|
+
"thin-content-too-short-no-cause",
|
|
355
|
+
false,
|
|
356
|
+
"did not throw",
|
|
357
|
+
);
|
|
358
|
+
} catch (error) {
|
|
359
|
+
const cause = (
|
|
360
|
+
error as { cause?: unknown }
|
|
361
|
+
).cause;
|
|
362
|
+
|
|
363
|
+
const message =
|
|
364
|
+
error instanceof Error
|
|
365
|
+
? error.message
|
|
366
|
+
: String(error);
|
|
367
|
+
|
|
368
|
+
add(
|
|
369
|
+
"thin-content-too-short-no-cause",
|
|
370
|
+
cause === undefined &&
|
|
371
|
+
message === "thin_content_detected",
|
|
372
|
+
`causePresent=${
|
|
373
|
+
cause !== undefined
|
|
374
|
+
} message=${message}`,
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 5. Empty response also has no salvageable cause.
|
|
380
|
+
{
|
|
381
|
+
const wrapped =
|
|
382
|
+
withSpaRescueFromRawResponse<string>(
|
|
383
|
+
async () => ({
|
|
384
|
+
value: "empty",
|
|
385
|
+
text: "",
|
|
386
|
+
contentType: "text/html",
|
|
387
|
+
canonicalUrl:
|
|
388
|
+
"https://empty.example.com/article",
|
|
389
|
+
bytesRead: 0,
|
|
390
|
+
}),
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
try {
|
|
394
|
+
await wrapped(
|
|
395
|
+
"https://empty.example.com/article",
|
|
396
|
+
mockCtx,
|
|
397
|
+
mockPolicy,
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
add(
|
|
401
|
+
"empty-html-no-cause",
|
|
402
|
+
false,
|
|
403
|
+
"did not throw",
|
|
404
|
+
);
|
|
405
|
+
} catch (error) {
|
|
406
|
+
const cause = (
|
|
407
|
+
error as { cause?: unknown }
|
|
408
|
+
).cause;
|
|
409
|
+
|
|
410
|
+
add(
|
|
411
|
+
"empty-html-no-cause",
|
|
412
|
+
cause === undefined,
|
|
413
|
+
`causePresent=${cause !== undefined}`,
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// 6. Plain failures are not converted into fabricated rescue payloads.
|
|
419
|
+
{
|
|
420
|
+
const wrapped =
|
|
421
|
+
withSpaRescueCause<string>(
|
|
422
|
+
async () => {
|
|
423
|
+
throw new Error(
|
|
424
|
+
"some_generic_failure",
|
|
425
|
+
);
|
|
426
|
+
},
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
try {
|
|
430
|
+
await wrapped(
|
|
431
|
+
"https://generic.example.com/article",
|
|
432
|
+
mockCtx,
|
|
433
|
+
mockPolicy,
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
add(
|
|
437
|
+
"no-cause-rethrows-unchanged",
|
|
438
|
+
false,
|
|
439
|
+
"did not throw",
|
|
440
|
+
);
|
|
441
|
+
} catch (error) {
|
|
442
|
+
const cause = (
|
|
443
|
+
error as { cause?: unknown }
|
|
444
|
+
).cause;
|
|
445
|
+
|
|
446
|
+
const message =
|
|
447
|
+
error instanceof Error
|
|
448
|
+
? error.message
|
|
449
|
+
: String(error);
|
|
450
|
+
|
|
451
|
+
add(
|
|
452
|
+
"no-cause-rethrows-unchanged",
|
|
453
|
+
message === "some_generic_failure" &&
|
|
454
|
+
cause === undefined,
|
|
455
|
+
`message=${message} causePresent=${
|
|
456
|
+
cause !== undefined
|
|
457
|
+
}`,
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// 7. A pre-existing, valid SPA rescue cause is preserved exactly.
|
|
463
|
+
{
|
|
464
|
+
const softHtml =
|
|
465
|
+
'<html><body><div id="__next"></div>' +
|
|
466
|
+
"y".repeat(240) +
|
|
467
|
+
"</body></html>";
|
|
468
|
+
|
|
469
|
+
const wrapped =
|
|
470
|
+
withSpaRescueCause<string>(
|
|
471
|
+
async () => {
|
|
472
|
+
const error = new Error(
|
|
473
|
+
"spa_shell_detected",
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
(
|
|
477
|
+
error as {
|
|
478
|
+
cause?: unknown;
|
|
479
|
+
}
|
|
480
|
+
).cause = softHtml;
|
|
481
|
+
|
|
482
|
+
throw error;
|
|
483
|
+
},
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
try {
|
|
487
|
+
await wrapped(
|
|
488
|
+
"https://soft.example.com/article",
|
|
489
|
+
mockCtx,
|
|
490
|
+
mockPolicy,
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
add(
|
|
494
|
+
"soft-cause-propagated",
|
|
495
|
+
false,
|
|
496
|
+
"did not throw",
|
|
497
|
+
);
|
|
498
|
+
} catch (error) {
|
|
499
|
+
const cause = (
|
|
500
|
+
error as { cause?: unknown }
|
|
501
|
+
).cause;
|
|
502
|
+
|
|
503
|
+
add(
|
|
504
|
+
"soft-cause-propagated",
|
|
505
|
+
cause === softHtml,
|
|
506
|
+
`causeMatches=${cause === softHtml}`,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// 8. A mistakenly attached challenge page must have its cause stripped.
|
|
512
|
+
{
|
|
513
|
+
const hardHtml =
|
|
514
|
+
'<html><body><div class="cf-challenge">' +
|
|
515
|
+
"Checking your browser. Turnstile verification required." +
|
|
516
|
+
"</div>" +
|
|
517
|
+
"z".repeat(180) +
|
|
518
|
+
"</body></html>";
|
|
519
|
+
|
|
520
|
+
const wrapped =
|
|
521
|
+
withSpaRescueCause<string>(
|
|
522
|
+
async () => {
|
|
523
|
+
const error = new Error(
|
|
524
|
+
"mislabeled_soft_failure",
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
(
|
|
528
|
+
error as {
|
|
529
|
+
cause?: unknown;
|
|
530
|
+
}
|
|
531
|
+
).cause = hardHtml;
|
|
532
|
+
|
|
533
|
+
throw error;
|
|
534
|
+
},
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
try {
|
|
538
|
+
await wrapped(
|
|
539
|
+
"https://hard.example.com/article",
|
|
540
|
+
mockCtx,
|
|
541
|
+
mockPolicy,
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
add(
|
|
545
|
+
"hard-cause-stripped",
|
|
546
|
+
false,
|
|
547
|
+
"did not throw",
|
|
548
|
+
);
|
|
549
|
+
} catch (error) {
|
|
550
|
+
const cause = (
|
|
551
|
+
error as { cause?: unknown }
|
|
552
|
+
).cause;
|
|
553
|
+
|
|
554
|
+
add(
|
|
555
|
+
"hard-cause-stripped",
|
|
556
|
+
cause === undefined,
|
|
557
|
+
cause === undefined
|
|
558
|
+
? "cause stripped"
|
|
559
|
+
: "hard challenge cause leaked",
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// 9. Non-Error thrown values are normalized without inventing data.
|
|
565
|
+
{
|
|
566
|
+
const wrapped =
|
|
567
|
+
withSpaRescueCause<string>(
|
|
568
|
+
async () => {
|
|
569
|
+
throw "raw_string_failure";
|
|
570
|
+
},
|
|
571
|
+
);
|
|
572
|
+
|
|
573
|
+
try {
|
|
574
|
+
await wrapped(
|
|
575
|
+
"https://nonerror.example.com/article",
|
|
576
|
+
mockCtx,
|
|
577
|
+
mockPolicy,
|
|
578
|
+
);
|
|
579
|
+
|
|
580
|
+
add(
|
|
581
|
+
"non-error-normalized",
|
|
582
|
+
false,
|
|
583
|
+
"did not throw",
|
|
584
|
+
);
|
|
585
|
+
} catch (error) {
|
|
586
|
+
add(
|
|
587
|
+
"non-error-normalized",
|
|
588
|
+
error instanceof Error &&
|
|
589
|
+
error.message ===
|
|
590
|
+
"raw_string_failure",
|
|
591
|
+
`isError=${
|
|
592
|
+
error instanceof Error
|
|
593
|
+
} message=${
|
|
594
|
+
error instanceof Error
|
|
595
|
+
? error.message
|
|
596
|
+
: String(error)
|
|
597
|
+
}`,
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
return {
|
|
603
|
+
ok: checks.every(
|
|
604
|
+
(check) => check.passed,
|
|
605
|
+
),
|
|
606
|
+
checks,
|
|
607
|
+
};
|
|
608
|
+
}
|