@theowlops/boombot 0.0.0-stage → 1.1.1
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/README.md +69 -3
- package/dist/LICENSE +21 -0
- package/dist/bin/boombot.js +16 -0
- package/dist/cli/api-key.js +123 -0
- package/dist/cli/bin-bun.js +17 -0
- package/dist/cli/bin.js +34 -0
- package/dist/cli/cli/cli-error.js +61 -0
- package/dist/cli/cli/dispatch.js +138 -0
- package/dist/cli/cli/help.js +83 -0
- package/dist/cli/cli/parser.js +89 -0
- package/dist/cli/cli/registry.js +185 -0
- package/dist/cli/cli/spec.js +41 -0
- package/dist/cli/cli/suggest.js +125 -0
- package/dist/cli/cli/version.js +30 -0
- package/dist/cli/cli/vocabulary.js +87 -0
- package/dist/cli/commands/doctor.js +365 -0
- package/dist/cli/commands/gateway.js +290 -0
- package/dist/cli/commands/migrate.js +270 -0
- package/dist/cli/commands/plugin.js +97 -0
- package/dist/cli/commands/setup.js +244 -0
- package/dist/cli/config-file.js +133 -0
- package/dist/cli/master-key.js +78 -0
- package/dist/cli/open-browser.js +59 -0
- package/dist/cli/web-assets.js +58 -0
- package/dist/gateway/auth.js +46 -0
- package/dist/gateway/config-format.js +202 -0
- package/dist/gateway/config.js +427 -0
- package/dist/gateway/context.js +1 -0
- package/dist/gateway/env-file.js +129 -0
- package/dist/gateway/events.js +172 -0
- package/dist/gateway/guard/tagging.js +505 -0
- package/dist/gateway/handlers/index.js +66 -0
- package/dist/gateway/handlers/memory.js +54 -0
- package/dist/gateway/handlers/providers.js +73 -0
- package/dist/gateway/handlers/registry.js +39 -0
- package/dist/gateway/handlers/sessions.js +188 -0
- package/dist/gateway/handlers/system.js +12 -0
- package/dist/gateway/handlers/tasks.js +191 -0
- package/dist/gateway/handlers/turn.js +100 -0
- package/dist/gateway/index.js +126 -0
- package/dist/gateway/main.js +23 -0
- package/dist/gateway/server.js +354 -0
- package/dist/gateway/services/context-limits.js +75 -0
- package/dist/gateway/services/history-normalizer.js +42 -0
- package/dist/gateway/services/image-pipeline.js +56 -0
- package/dist/gateway/services/key-roulette-client.js +43 -0
- package/dist/gateway/services/llm-client.js +593 -0
- package/dist/gateway/services/llm-decoder.js +200 -0
- package/dist/gateway/services/local-fallback.js +135 -0
- package/dist/gateway/services/memory.js +511 -0
- package/dist/gateway/services/persistent-memory.js +196 -0
- package/dist/gateway/services/providers.js +44 -0
- package/dist/gateway/services/tasks.js +237 -0
- package/dist/gateway/services/verification.js +124 -0
- package/dist/gateway/services/vision-payload.js +48 -0
- package/dist/gateway/services.js +257 -0
- package/dist/gateway/session-snapshot.js +19 -0
- package/dist/gateway/sessions.js +701 -0
- package/dist/gateway/static.js +239 -0
- package/dist/gateway/turns/clarify-tool.js +57 -0
- package/dist/gateway/turns/cronjob-tool.js +96 -0
- package/dist/gateway/turns/deferred-tools.js +154 -0
- package/dist/gateway/turns/execute-code-tool.js +84 -0
- package/dist/gateway/turns/file-tool-defs.js +178 -0
- package/dist/gateway/turns/file-tool-ops.js +178 -0
- package/dist/gateway/turns/file-tool-scan.js +182 -0
- package/dist/gateway/turns/file-tool.js +302 -0
- package/dist/gateway/turns/index.js +416 -0
- package/dist/gateway/turns/jev-middleware.js +91 -0
- package/dist/gateway/turns/local-reply.js +156 -0
- package/dist/gateway/turns/mcp-client.js +643 -0
- package/dist/gateway/turns/memory-tool.js +171 -0
- package/dist/gateway/turns/middleware.js +96 -0
- package/dist/gateway/turns/python-core.js +397 -0
- package/dist/gateway/turns/routing/index.js +3 -0
- package/dist/gateway/turns/routing/intent-classifier.js +60 -0
- package/dist/gateway/turns/routing/planner-adapter.js +91 -0
- package/dist/gateway/turns/routing/types.js +1 -0
- package/dist/gateway/turns/runtime-deps.js +228 -0
- package/dist/gateway/turns/self-config-tool.js +277 -0
- package/dist/gateway/turns/service-types.js +11 -0
- package/dist/gateway/turns/service.js +820 -0
- package/dist/gateway/turns/session-adapter.js +158 -0
- package/dist/gateway/turns/session-tool.js +49 -0
- package/dist/gateway/turns/shell-tool.js +190 -0
- package/dist/gateway/turns/skill-tool.js +239 -0
- package/dist/gateway/turns/spillover.js +201 -0
- package/dist/gateway/turns/subagent-tool.js +140 -0
- package/dist/gateway/turns/system-prompt.js +121 -0
- package/dist/gateway/turns/tool-schema.js +90 -0
- package/dist/gateway/turns/turn-utils.js +58 -0
- package/dist/gateway/turns/vision-tool.js +120 -0
- package/dist/gateway/types.js +1 -0
- package/dist/native/win32-x64/boombot-native-host.exe +0 -0
- package/dist/node_modules/@boombot/channels/handlers.d.ts +9 -0
- package/dist/node_modules/@boombot/channels/handlers.js +109 -0
- package/dist/node_modules/@boombot/channels/index.d.ts +12 -0
- package/dist/node_modules/@boombot/channels/index.js +12 -0
- package/dist/node_modules/@boombot/channels/package.json +9 -0
- package/dist/node_modules/@boombot/channels/service.d.ts +62 -0
- package/dist/node_modules/@boombot/channels/service.js +608 -0
- package/dist/node_modules/@boombot/channels/tool.d.ts +10 -0
- package/dist/node_modules/@boombot/channels/tool.js +46 -0
- package/dist/node_modules/@boombot/channels/transports/common/dedup.d.ts +17 -0
- package/dist/node_modules/@boombot/channels/transports/common/dedup.js +42 -0
- package/dist/node_modules/@boombot/channels/transports/common/handoff.d.ts +19 -0
- package/dist/node_modules/@boombot/channels/transports/common/handoff.js +32 -0
- package/dist/node_modules/@boombot/channels/transports/common/index.d.ts +3 -0
- package/dist/node_modules/@boombot/channels/transports/common/index.js +3 -0
- package/dist/node_modules/@boombot/channels/transports/common/types.d.ts +99 -0
- package/dist/node_modules/@boombot/channels/transports/common/types.js +54 -0
- package/dist/node_modules/@boombot/channels/transports/common.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/common.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/dedup/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/dedup/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/dedup.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/dedup.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/discord/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/discord/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/discord/transport.d.ts +36 -0
- package/dist/node_modules/@boombot/channels/transports/discord/transport.js +199 -0
- package/dist/node_modules/@boombot/channels/transports/discord.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/discord.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/handoff.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/handoff.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/transport.d.ts +34 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/transport.js +180 -0
- package/dist/node_modules/@boombot/channels/transports/messenger.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/messenger.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/slack/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/slack/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/slack/transport.d.ts +35 -0
- package/dist/node_modules/@boombot/channels/transports/slack/transport.js +183 -0
- package/dist/node_modules/@boombot/channels/transports/slack.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/slack.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/streamer.d.ts +31 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/streamer.js +141 -0
- package/dist/node_modules/@boombot/channels/transports/streamer.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/streamer.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/transport.d.ts +75 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/transport.js +395 -0
- package/dist/node_modules/@boombot/channels/transports/telegram.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/telegram.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/transport.d.ts +27 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/transport.js +97 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.d.ts +38 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.js +189 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/index.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/index.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/oa.d.ts +28 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/oa.js +94 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/personal.d.ts +106 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/personal.js +171 -0
- package/dist/node_modules/@boombot/channels/transports/zalo-personal.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo-personal.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo.js +2 -0
- package/dist/node_modules/@boombot/core/agent-core/index.d.ts +12 -0
- package/dist/node_modules/@boombot/core/agent-core/index.js +12 -0
- package/dist/node_modules/@boombot/core/agent-core/middleware.d.ts +60 -0
- package/dist/node_modules/@boombot/core/agent-core/middleware.js +152 -0
- package/dist/node_modules/@boombot/core/agent-core/routing.d.ts +128 -0
- package/dist/node_modules/@boombot/core/agent-core/routing.js +437 -0
- package/dist/node_modules/@boombot/core/agent-core/runtime-deps.d.ts +88 -0
- package/dist/node_modules/@boombot/core/agent-core/runtime-deps.js +8 -0
- package/dist/node_modules/@boombot/core/agent-core/tool-errors.d.ts +44 -0
- package/dist/node_modules/@boombot/core/agent-core/tool-errors.js +60 -0
- package/dist/node_modules/@boombot/core/agent-core/turn-loop.d.ts +21 -0
- package/dist/node_modules/@boombot/core/agent-core/turn-loop.js +561 -0
- package/dist/node_modules/@boombot/core/agent-core/types.d.ts +189 -0
- package/dist/node_modules/@boombot/core/agent-core/types.js +7 -0
- package/dist/node_modules/@boombot/core/compaction/compactor.d.ts +19 -0
- package/dist/node_modules/@boombot/core/compaction/compactor.js +127 -0
- package/dist/node_modules/@boombot/core/compaction/estimator.d.ts +10 -0
- package/dist/node_modules/@boombot/core/compaction/estimator.js +48 -0
- package/dist/node_modules/@boombot/core/compaction/index.d.ts +3 -0
- package/dist/node_modules/@boombot/core/compaction/index.js +3 -0
- package/dist/node_modules/@boombot/core/compaction/types.d.ts +31 -0
- package/dist/node_modules/@boombot/core/compaction/types.js +7 -0
- package/dist/node_modules/@boombot/core/index.d.ts +9 -0
- package/dist/node_modules/@boombot/core/index.js +9 -0
- package/dist/node_modules/@boombot/core/jev/index.d.ts +2 -0
- package/dist/node_modules/@boombot/core/jev/index.js +2 -0
- package/dist/node_modules/@boombot/core/jev/jev.d.ts +30 -0
- package/dist/node_modules/@boombot/core/jev/jev.js +164 -0
- package/dist/node_modules/@boombot/core/jev/types.d.ts +22 -0
- package/dist/node_modules/@boombot/core/jev/types.js +1 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/budget.d.ts +63 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/budget.js +94 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.d.ts +152 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.js +318 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/index.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/index.js +12 -0
- package/dist/node_modules/@boombot/core/memory/curation.d.ts +86 -0
- package/dist/node_modules/@boombot/core/memory/curation.js +120 -0
- package/dist/node_modules/@boombot/core/memory/errors.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/errors.js +20 -0
- package/dist/node_modules/@boombot/core/memory/hybrid-search.d.ts +29 -0
- package/dist/node_modules/@boombot/core/memory/hybrid-search.js +52 -0
- package/dist/node_modules/@boombot/core/memory/index.d.ts +23 -0
- package/dist/node_modules/@boombot/core/memory/index.js +23 -0
- package/dist/node_modules/@boombot/core/memory/indexer.d.ts +47 -0
- package/dist/node_modules/@boombot/core/memory/indexer.js +138 -0
- package/dist/node_modules/@boombot/core/memory/lifecycle.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/lifecycle.js +66 -0
- package/dist/node_modules/@boombot/core/memory/provider.d.ts +84 -0
- package/dist/node_modules/@boombot/core/memory/provider.js +117 -0
- package/dist/node_modules/@boombot/core/memory/recall.d.ts +7 -0
- package/dist/node_modules/@boombot/core/memory/recall.js +111 -0
- package/dist/node_modules/@boombot/core/memory/scope-resolver.d.ts +27 -0
- package/dist/node_modules/@boombot/core/memory/scope-resolver.js +60 -0
- package/dist/node_modules/@boombot/core/memory/search.d.ts +37 -0
- package/dist/node_modules/@boombot/core/memory/search.js +158 -0
- package/dist/node_modules/@boombot/core/memory/store.d.ts +60 -0
- package/dist/node_modules/@boombot/core/memory/store.js +289 -0
- package/dist/node_modules/@boombot/core/memory/types.d.ts +121 -0
- package/dist/node_modules/@boombot/core/memory/types.js +21 -0
- package/dist/node_modules/@boombot/core/memory/vector-index.d.ts +34 -0
- package/dist/node_modules/@boombot/core/memory/vector-index.js +65 -0
- package/dist/node_modules/@boombot/core/package.json +9 -0
- package/dist/node_modules/@boombot/core/reflection/classifier.d.ts +13 -0
- package/dist/node_modules/@boombot/core/reflection/classifier.js +77 -0
- package/dist/node_modules/@boombot/core/reflection/index.d.ts +2 -0
- package/dist/node_modules/@boombot/core/reflection/index.js +2 -0
- package/dist/node_modules/@boombot/core/reflection/types.d.ts +13 -0
- package/dist/node_modules/@boombot/core/reflection/types.js +4 -0
- package/dist/node_modules/@boombot/core/research/config.d.ts +89 -0
- package/dist/node_modules/@boombot/core/research/config.js +206 -0
- package/dist/node_modules/@boombot/core/research/crawl.d.ts +36 -0
- package/dist/node_modules/@boombot/core/research/crawl.js +179 -0
- package/dist/node_modules/@boombot/core/research/factory.d.ts +26 -0
- package/dist/node_modules/@boombot/core/research/factory.js +46 -0
- package/dist/node_modules/@boombot/core/research/http.d.ts +87 -0
- package/dist/node_modules/@boombot/core/research/http.js +250 -0
- package/dist/node_modules/@boombot/core/research/index.d.ts +17 -0
- package/dist/node_modules/@boombot/core/research/index.js +10 -0
- package/dist/node_modules/@boombot/core/research/orchestrator.d.ts +113 -0
- package/dist/node_modules/@boombot/core/research/orchestrator.js +252 -0
- package/dist/node_modules/@boombot/core/research/parse/docx.d.ts +24 -0
- package/dist/node_modules/@boombot/core/research/parse/docx.js +183 -0
- package/dist/node_modules/@boombot/core/research/parse/guards.d.ts +89 -0
- package/dist/node_modules/@boombot/core/research/parse/guards.js +171 -0
- package/dist/node_modules/@boombot/core/research/parse/index.d.ts +68 -0
- package/dist/node_modules/@boombot/core/research/parse/index.js +219 -0
- package/dist/node_modules/@boombot/core/research/parse/pdf.d.ts +38 -0
- package/dist/node_modules/@boombot/core/research/parse/pdf.js +567 -0
- package/dist/node_modules/@boombot/core/research/providers/arxiv.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/arxiv.js +72 -0
- package/dist/node_modules/@boombot/core/research/providers/brave.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/brave.js +36 -0
- package/dist/node_modules/@boombot/core/research/providers/duckduckgo.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/duckduckgo.js +78 -0
- package/dist/node_modules/@boombot/core/research/providers/exa.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/exa.js +34 -0
- package/dist/node_modules/@boombot/core/research/providers/firecrawl.d.ts +16 -0
- package/dist/node_modules/@boombot/core/research/providers/firecrawl.js +47 -0
- package/dist/node_modules/@boombot/core/research/providers/index.d.ts +17 -0
- package/dist/node_modules/@boombot/core/research/providers/index.js +11 -0
- package/dist/node_modules/@boombot/core/research/providers/jina.d.ts +13 -0
- package/dist/node_modules/@boombot/core/research/providers/jina.js +114 -0
- package/dist/node_modules/@boombot/core/research/providers/openalex.d.ts +14 -0
- package/dist/node_modules/@boombot/core/research/providers/openalex.js +66 -0
- package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.js +56 -0
- package/dist/node_modules/@boombot/core/research/providers/tavily.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/tavily.js +35 -0
- package/dist/node_modules/@boombot/core/research/providers/wikipedia.d.ts +12 -0
- package/dist/node_modules/@boombot/core/research/providers/wikipedia.js +47 -0
- package/dist/node_modules/@boombot/core/research/tools.d.ts +27 -0
- package/dist/node_modules/@boombot/core/research/tools.js +251 -0
- package/dist/node_modules/@boombot/core/research/types.d.ts +133 -0
- package/dist/node_modules/@boombot/core/research/types.js +8 -0
- package/dist/node_modules/@boombot/core/research/wiring.d.ts +25 -0
- package/dist/node_modules/@boombot/core/research/wiring.js +51 -0
- package/dist/node_modules/@boombot/core/scheduler/cron.d.ts +34 -0
- package/dist/node_modules/@boombot/core/scheduler/cron.js +147 -0
- package/dist/node_modules/@boombot/core/scheduler/evaluator.d.ts +42 -0
- package/dist/node_modules/@boombot/core/scheduler/evaluator.js +148 -0
- package/dist/node_modules/@boombot/core/scheduler/index.d.ts +15 -0
- package/dist/node_modules/@boombot/core/scheduler/index.js +15 -0
- package/dist/node_modules/@boombot/core/scheduler/registry.d.ts +81 -0
- package/dist/node_modules/@boombot/core/scheduler/registry.js +263 -0
- package/dist/node_modules/@boombot/core/scheduler/runner.d.ts +59 -0
- package/dist/node_modules/@boombot/core/scheduler/runner.js +257 -0
- package/dist/node_modules/@boombot/core/scheduler/store.d.ts +150 -0
- package/dist/node_modules/@boombot/core/scheduler/store.js +526 -0
- package/dist/node_modules/@boombot/core/scheduler/timezone.d.ts +35 -0
- package/dist/node_modules/@boombot/core/scheduler/timezone.js +96 -0
- package/dist/node_modules/@boombot/core/scheduler/types.d.ts +157 -0
- package/dist/node_modules/@boombot/core/scheduler/types.js +89 -0
- package/dist/node_modules/@boombot/core/task-runner/index.d.ts +7 -0
- package/dist/node_modules/@boombot/core/task-runner/index.js +5 -0
- package/dist/node_modules/@boombot/core/task-runner/planner.d.ts +37 -0
- package/dist/node_modules/@boombot/core/task-runner/planner.js +154 -0
- package/dist/node_modules/@boombot/core/task-runner/runner.d.ts +8 -0
- package/dist/node_modules/@boombot/core/task-runner/runner.js +564 -0
- package/dist/node_modules/@boombot/core/task-runner/store.d.ts +28 -0
- package/dist/node_modules/@boombot/core/task-runner/store.js +126 -0
- package/dist/node_modules/@boombot/core/task-runner/types.d.ts +138 -0
- package/dist/node_modules/@boombot/core/task-runner/types.js +11 -0
- package/dist/node_modules/@boombot/core/workflow/dag.d.ts +16 -0
- package/dist/node_modules/@boombot/core/workflow/dag.js +109 -0
- package/dist/node_modules/@boombot/core/workflow/engine.d.ts +34 -0
- package/dist/node_modules/@boombot/core/workflow/engine.js +304 -0
- package/dist/node_modules/@boombot/core/workflow/index.d.ts +3 -0
- package/dist/node_modules/@boombot/core/workflow/index.js +3 -0
- package/dist/node_modules/@boombot/core/workflow/types.d.ts +98 -0
- package/dist/node_modules/@boombot/core/workflow/types.js +21 -0
- package/dist/node_modules/@boombot/cronjobs/handlers.d.ts +11 -0
- package/dist/node_modules/@boombot/cronjobs/handlers.js +174 -0
- package/dist/node_modules/@boombot/cronjobs/index.d.ts +2 -0
- package/dist/node_modules/@boombot/cronjobs/index.js +2 -0
- package/dist/node_modules/@boombot/cronjobs/package.json +9 -0
- package/dist/node_modules/@boombot/cronjobs/service.d.ts +53 -0
- package/dist/node_modules/@boombot/cronjobs/service.js +200 -0
- package/dist/node_modules/@boombot/plugins/index.d.ts +2 -0
- package/dist/node_modules/@boombot/plugins/index.js +2 -0
- package/dist/node_modules/@boombot/plugins/installer.d.ts +45 -0
- package/dist/node_modules/@boombot/plugins/installer.js +487 -0
- package/dist/node_modules/@boombot/plugins/manager.d.ts +23 -0
- package/dist/node_modules/@boombot/plugins/manager.js +243 -0
- package/dist/node_modules/@boombot/plugins/package.json +9 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.d.ts +125 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.js +76 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.d.ts +220 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.js +60 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.d.ts +33 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.js +25 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.d.ts +4349 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.js +563 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.d.ts +32 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.js +61 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.d.ts +13 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.js +16 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/events.d.ts +567 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/events.js +395 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/index.d.ts +20 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/index.js +13 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/types.d.ts +91 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/types.js +7 -0
- package/dist/node_modules/@boombot/protocol/index.d.ts +4 -0
- package/dist/node_modules/@boombot/protocol/index.js +3 -0
- package/dist/node_modules/@boombot/protocol/package.json +9 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.d.ts +41 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.js +17 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/index.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/index.js +10 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.d.ts +58 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.js +116 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.d.ts +25 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.js +1 -0
- package/dist/node_modules/@boombot/protocol/providers/cipher.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/cipher.js +52 -0
- package/dist/node_modules/@boombot/protocol/providers/index.d.ts +19 -0
- package/dist/node_modules/@boombot/protocol/providers/index.js +19 -0
- package/dist/node_modules/@boombot/protocol/providers/key-roulette.d.ts +79 -0
- package/dist/node_modules/@boombot/protocol/providers/key-roulette.js +81 -0
- package/dist/node_modules/@boombot/protocol/providers/probe.d.ts +29 -0
- package/dist/node_modules/@boombot/protocol/providers/probe.js +96 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.d.ts +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/custom.d.ts +22 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/custom.js +222 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.js +9 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/google.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/google.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/index.d.ts +31 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/index.js +56 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/local.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/local.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.js +9 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/types.d.ts +58 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/types.js +1 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/xai.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/xai.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/request-profile.d.ts +102 -0
- package/dist/node_modules/@boombot/protocol/providers/request-profile.js +118 -0
- package/dist/node_modules/@boombot/protocol/providers/service.d.ts +2 -0
- package/dist/node_modules/@boombot/protocol/providers/service.js +418 -0
- package/dist/node_modules/@boombot/protocol/providers/types.d.ts +141 -0
- package/dist/node_modules/@boombot/protocol/providers/types.js +16 -0
- package/dist/node_modules/@boombot/sandbox/fs-path.d.ts +13 -0
- package/dist/node_modules/@boombot/sandbox/fs-path.js +79 -0
- package/dist/node_modules/@boombot/sandbox/index.d.ts +13 -0
- package/dist/node_modules/@boombot/sandbox/index.js +13 -0
- package/dist/node_modules/@boombot/sandbox/native.d.ts +39 -0
- package/dist/node_modules/@boombot/sandbox/native.js +224 -0
- package/dist/node_modules/@boombot/sandbox/package.json +9 -0
- package/dist/node_modules/@boombot/sandbox/sandbox.d.ts +92 -0
- package/dist/node_modules/@boombot/sandbox/sandbox.js +229 -0
- package/dist/node_modules/@boombot/security/harness-guard/boundary.d.ts +22 -0
- package/dist/node_modules/@boombot/security/harness-guard/boundary.js +105 -0
- package/dist/node_modules/@boombot/security/harness-guard/gates.d.ts +90 -0
- package/dist/node_modules/@boombot/security/harness-guard/gates.js +791 -0
- package/dist/node_modules/@boombot/security/harness-guard/index.d.ts +23 -0
- package/dist/node_modules/@boombot/security/harness-guard/index.js +23 -0
- package/dist/node_modules/@boombot/security/harness-guard/policy.d.ts +20 -0
- package/dist/node_modules/@boombot/security/harness-guard/policy.js +70 -0
- package/dist/node_modules/@boombot/security/harness-guard/sanitizer.d.ts +53 -0
- package/dist/node_modules/@boombot/security/harness-guard/sanitizer.js +145 -0
- package/dist/node_modules/@boombot/security/harness-guard/types.d.ts +71 -0
- package/dist/node_modules/@boombot/security/harness-guard/types.js +10 -0
- package/dist/node_modules/@boombot/security/harness-guard/verifier.d.ts +59 -0
- package/dist/node_modules/@boombot/security/harness-guard/verifier.js +169 -0
- package/dist/node_modules/@boombot/security/index.d.ts +5 -0
- package/dist/node_modules/@boombot/security/index.js +9 -0
- package/dist/node_modules/@boombot/security/package.json +9 -0
- package/dist/node_modules/@boombot/security/policy/approval.d.ts +117 -0
- package/dist/node_modules/@boombot/security/policy/approval.js +223 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.d.ts +10 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.js +124 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.d.ts +25 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.js +70 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/gate.d.ts +38 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/gate.js +61 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.d.ts +12 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.js +234 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/index.d.ts +17 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/index.js +13 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/policy.d.ts +15 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/policy.js +39 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/types.d.ts +46 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/types.js +7 -0
- package/dist/node_modules/@boombot/security/security/approval.d.ts +63 -0
- package/dist/node_modules/@boombot/security/security/approval.js +140 -0
- package/dist/node_modules/@boombot/security/security/audit.d.ts +39 -0
- package/dist/node_modules/@boombot/security/security/audit.js +70 -0
- package/dist/node_modules/@boombot/security/security/index.d.ts +12 -0
- package/dist/node_modules/@boombot/security/security/index.js +12 -0
- package/dist/node_modules/@boombot/security/security/trust.d.ts +79 -0
- package/dist/node_modules/@boombot/security/security/trust.js +87 -0
- package/dist/package.json +5 -0
- package/dist/proto/agent_core.proto +56 -0
- package/dist/python/agent-core-python/pyproject.toml +40 -0
- package/dist/python/agent-core-python/src/boombot_agent/__init__.py +5 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/__init__.py +0 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2.py +54 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2_grpc.py +140 -0
- package/dist/python/agent-core-python/src/boombot_agent/rpc.py +265 -0
- package/dist/python/agent-core-python/src/boombot_agent/turn.py +577 -0
- package/dist/python/agent-core-python/src/boombot_ml/__init__.py +12 -0
- package/dist/python/agent-core-python/src/boombot_ml/embeddings.py +58 -0
- package/dist/python/agent-core-python/src/boombot_ml/training.py +156 -0
- package/dist/python/agent-core-python/uv.lock +2856 -0
- package/dist/web/assets/ChatView-BZrSD-64.js +262 -0
- package/dist/web/assets/ChatView-Cahbjez6.css +1 -0
- package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/web/assets/MemoryView-BJbXqqs7.css +1 -0
- package/dist/web/assets/MemoryView-BfMq_6CD.js +1 -0
- package/dist/web/assets/SchedulesView-B22QmPR-.js +1 -0
- package/dist/web/assets/SchedulesView-C6XK7A8a.css +1 -0
- package/dist/web/assets/SessionsView-C1dqdhxI.css +1 -0
- package/dist/web/assets/SessionsView-DS0-aH2a.js +1 -0
- package/dist/web/assets/TasksView-Dtasg4hd.css +1 -0
- package/dist/web/assets/TasksView-ey0FLsW8.js +2 -0
- package/dist/web/assets/Textarea-DN3Zybl1.js +1 -0
- package/dist/web/assets/Tooltip-Bn2cqFPz.css +1 -0
- package/dist/web/assets/Tooltip-MzV2Gqnc.js +1 -0
- package/dist/web/assets/browser-Bnt73-Ub.js +8 -0
- package/dist/web/assets/index-BL8bi7Yt.css +1 -0
- package/dist/web/assets/index-CuPR73Tn.js +73 -0
- package/dist/web/favicon.svg +4 -0
- package/dist/web/index.html +26 -0
- package/dist/web/logo.jpg +0 -0
- package/dist/web/logo.png +0 -0
- package/package.json +51 -4
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security guards for document parsing (`research.parse`).
|
|
3
|
+
*
|
|
4
|
+
* Parsing attacker-influenced bytes — a URL the model or user asked
|
|
5
|
+
* `research.extract` to read — is an attack surface: zip bombs, decompression
|
|
6
|
+
* bombs hidden in PDF content streams, and absurd entry counts. This module
|
|
7
|
+
* is the choke point every parser runs through: the same role
|
|
8
|
+
* `sanitizeExtractUrl` plays for URL inputs in `orchestrator.extract()`.
|
|
9
|
+
*
|
|
10
|
+
* Two lines of defense, because declared sizes are attacker-controlled:
|
|
11
|
+
* 1. Declared sizes are checked BEFORE inflating — cheaply rejects 42.zip-style
|
|
12
|
+
* entries whose headers claim gigabytes.
|
|
13
|
+
* 2. Actual output bytes are counted DURING streaming inflation — closes the
|
|
14
|
+
* understated/zero-size hole (the adm-zip CVE-2026-77301 class of bug, where
|
|
15
|
+
* a streaming path never checked accumulated output).
|
|
16
|
+
*
|
|
17
|
+
* Fail-closed: any cap breach throws `DocumentParseError`; a parser never
|
|
18
|
+
* returns a partial buffer.
|
|
19
|
+
*/
|
|
20
|
+
import { createInflate, createInflateRaw, } from 'node:zlib';
|
|
21
|
+
export class DocumentParseError extends Error {
|
|
22
|
+
code;
|
|
23
|
+
constructor(code, message, options) {
|
|
24
|
+
super(message, options);
|
|
25
|
+
this.name = 'DocumentParseError';
|
|
26
|
+
this.code = code;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Hard cap on raw document bytes accepted for parsing. Matches
|
|
31
|
+
* `DEFAULT_MAX_RESPONSE_BYTES` in `../http.ts` so a document fetch can never
|
|
32
|
+
* exceed what a normal extract response may already hold.
|
|
33
|
+
*/
|
|
34
|
+
export const MAX_DOCUMENT_BYTES = 5_242_880; // 5 MiB
|
|
35
|
+
/** Max entries in a ZIP central directory — a docx rarely has a few hundred. */
|
|
36
|
+
export const MAX_ZIP_ENTRIES = 2048;
|
|
37
|
+
/** Max declared uncompressed size of a single ZIP entry. */
|
|
38
|
+
export const MAX_ZIP_ENTRY_BYTES = 20_971_520; // 20 MiB
|
|
39
|
+
/** Max total decompressed bytes across every inflated entry/stream of one document. */
|
|
40
|
+
export const MAX_TOTAL_DECOMPRESSED_BYTES = 52_428_800; // 50 MiB
|
|
41
|
+
/**
|
|
42
|
+
* Declared compression ratio above this is treated as a bomb. Legitimate
|
|
43
|
+
* docx XML compresses ~5–20:1; real zip bombs start around 100,000:1, so
|
|
44
|
+
* 100:1 rejects every known bomb shape with wide margin for legit files.
|
|
45
|
+
*/
|
|
46
|
+
export const MAX_COMPRESSION_RATIO = 100;
|
|
47
|
+
/** Max content streams inflated from a single PDF. */
|
|
48
|
+
export const MAX_PDF_STREAMS = 20_000;
|
|
49
|
+
/**
|
|
50
|
+
* Ceiling on extracted plain-text characters — defense-in-depth past the
|
|
51
|
+
* byte quotas, so parser output can never blow up turn context on its own.
|
|
52
|
+
*/
|
|
53
|
+
export const MAX_EXTRACTED_CHARS = 200_000;
|
|
54
|
+
/** Reject an input buffer that exceeds {@link MAX_DOCUMENT_BYTES}. */
|
|
55
|
+
export function assertDocumentSize(byteLength, label = 'document') {
|
|
56
|
+
if (byteLength > MAX_DOCUMENT_BYTES) {
|
|
57
|
+
throw new DocumentParseError('DOCUMENT_TOO_LARGE', `${label} is ${byteLength} bytes; document parsing is capped at ${MAX_DOCUMENT_BYTES} bytes.`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check a ZIP entry's DECLARED sizes before touching its data.
|
|
62
|
+
* Cheap first line of defense — rejects 42.zip-style headers outright.
|
|
63
|
+
*/
|
|
64
|
+
export function assertDeclaredEntrySizes(args) {
|
|
65
|
+
const { compressedSize, uncompressedSize, method, label } = args;
|
|
66
|
+
if (uncompressedSize > MAX_ZIP_ENTRY_BYTES) {
|
|
67
|
+
throw new DocumentParseError('ARCHIVE_LIMIT', `ZIP entry '${label}' declares ${uncompressedSize} uncompressed bytes (cap ${MAX_ZIP_ENTRY_BYTES}).`);
|
|
68
|
+
}
|
|
69
|
+
if (method === 8) {
|
|
70
|
+
if (compressedSize === 0) {
|
|
71
|
+
// The size-0 bypass: a deflated entry with no compressed bytes can
|
|
72
|
+
// still expand (or is simply malformed). Only a truly empty entry
|
|
73
|
+
// (0 → 0) is allowed through.
|
|
74
|
+
if (uncompressedSize !== 0) {
|
|
75
|
+
throw new DocumentParseError('ARCHIVE_LIMIT', `ZIP entry '${label}' is deflated but declares 0 compressed bytes (possible bomb).`);
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const ratio = uncompressedSize / compressedSize;
|
|
80
|
+
if (ratio > MAX_COMPRESSION_RATIO) {
|
|
81
|
+
throw new DocumentParseError('ARCHIVE_LIMIT', `ZIP entry '${label}' declares a ${Math.round(ratio)}:1 compression ratio ` +
|
|
82
|
+
`(cap ${MAX_COMPRESSION_RATIO}:1, possible zip bomb).`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else if (method === 0) {
|
|
86
|
+
if (compressedSize !== uncompressedSize) {
|
|
87
|
+
throw new DocumentParseError('CORRUPT_DOCUMENT', `ZIP entry '${label}' is stored but compressed size ${compressedSize} ` +
|
|
88
|
+
`!= uncompressed size ${uncompressedSize}.`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
throw new DocumentParseError('UNSUPPORTED_TYPE', `ZIP entry '${label}' uses compression method ${method} (only stored/deflated are supported).`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Tracks the running total of decompressed bytes for one document and
|
|
97
|
+
* inflates raw-deflate blocks with both per-entry and total caps enforced
|
|
98
|
+
* DURING decompression (streaming). Declared sizes are attacker-controlled,
|
|
99
|
+
* so this second line of defense measures actual output — an entry that
|
|
100
|
+
* understates its size still trips the cap mid-inflate instead of landing
|
|
101
|
+
* a huge buffer in memory first.
|
|
102
|
+
*/
|
|
103
|
+
export class DecompressionQuota {
|
|
104
|
+
#usedTotal = 0;
|
|
105
|
+
/** Bytes inflated so far across all entries/streams of this document. */
|
|
106
|
+
get usedTotal() {
|
|
107
|
+
return this.#usedTotal;
|
|
108
|
+
}
|
|
109
|
+
/** Account `byteLength` raw (stored, not inflated) bytes against the total quota. */
|
|
110
|
+
trackRaw(byteLength, label) {
|
|
111
|
+
this.#usedTotal += byteLength;
|
|
112
|
+
if (this.#usedTotal > MAX_TOTAL_DECOMPRESSED_BYTES) {
|
|
113
|
+
throw new DocumentParseError('ARCHIVE_LIMIT', `Decompression quota exceeded reading '${label}' (possible zip bomb): ` +
|
|
114
|
+
`document total ${this.#usedTotal} bytes (cap ${MAX_TOTAL_DECOMPRESSED_BYTES}).`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Inflate one deflate block through `inflater`. Rejects with `ARCHIVE_LIMIT`
|
|
119
|
+
* when the entry would exceed `maxEntryBytes` or the document would exceed
|
|
120
|
+
* {@link MAX_TOTAL_DECOMPRESSED_BYTES}.
|
|
121
|
+
*/
|
|
122
|
+
#runInflate(inflater, compressed, maxEntryBytes, label) {
|
|
123
|
+
return new Promise((resolve, reject) => {
|
|
124
|
+
const chunks = [];
|
|
125
|
+
let entryBytes = 0;
|
|
126
|
+
let settled = false;
|
|
127
|
+
const fail = (err) => {
|
|
128
|
+
if (settled)
|
|
129
|
+
return;
|
|
130
|
+
settled = true;
|
|
131
|
+
inflater.destroy();
|
|
132
|
+
reject(err);
|
|
133
|
+
};
|
|
134
|
+
inflater.on('data', (chunk) => {
|
|
135
|
+
entryBytes += chunk.length;
|
|
136
|
+
this.#usedTotal += chunk.length;
|
|
137
|
+
if (entryBytes > maxEntryBytes ||
|
|
138
|
+
this.#usedTotal > MAX_TOTAL_DECOMPRESSED_BYTES) {
|
|
139
|
+
fail(new DocumentParseError('ARCHIVE_LIMIT', `Decompression quota exceeded while inflating '${label}' (possible zip bomb): ` +
|
|
140
|
+
`entry ${entryBytes} bytes (cap ${maxEntryBytes}), ` +
|
|
141
|
+
`document total ${this.#usedTotal} bytes (cap ${MAX_TOTAL_DECOMPRESSED_BYTES}).`));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
chunks.push(chunk);
|
|
145
|
+
});
|
|
146
|
+
inflater.on('end', () => {
|
|
147
|
+
if (settled)
|
|
148
|
+
return;
|
|
149
|
+
settled = true;
|
|
150
|
+
resolve(Buffer.concat(chunks));
|
|
151
|
+
});
|
|
152
|
+
inflater.on('error', (err) => {
|
|
153
|
+
fail(new DocumentParseError('CORRUPT_DOCUMENT', `Failed to inflate '${label}': ${err.message}.`));
|
|
154
|
+
});
|
|
155
|
+
inflater.end(compressed);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Inflate one zlib-wrapped deflate block (PDF `/FlateDecode` is zlib /
|
|
160
|
+
* RFC 1950 per the PDF spec, NOT raw deflate).
|
|
161
|
+
*/
|
|
162
|
+
inflate(compressed, maxEntryBytes, label) {
|
|
163
|
+
return this.#runInflate(createInflate(), compressed, maxEntryBytes, label);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Inflate one raw deflate block (ZIP entry data has no zlib wrapper).
|
|
167
|
+
*/
|
|
168
|
+
inflateRaw(compressed, maxEntryBytes, label) {
|
|
169
|
+
return this.#runInflate(createInflateRaw(), compressed, maxEntryBytes, label);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `research.parse` — zero-dependency document parsing for research.
|
|
3
|
+
*
|
|
4
|
+
* `parseDocument(bytes, mimeType)` extracts text from PDF and DOCX without
|
|
5
|
+
* any npm dependency (only `node:zlib` for decompression, quota-guarded in
|
|
6
|
+
* `./guards.ts`). `extractDocument()` is the fetch-level entry the
|
|
7
|
+
* orchestrator calls: it downloads the URL with a hard byte cap, sniffs the
|
|
8
|
+
* magic bytes, and parses — or hands back to the regular extract backend
|
|
9
|
+
* when the bytes are not actually a document.
|
|
10
|
+
*
|
|
11
|
+
* Security posture (parse = attack surface):
|
|
12
|
+
* - Every input passes `./guards.ts` caps (file size, entry count, declared
|
|
13
|
+
* + actual decompression quotas) — the input-side choke point, mirroring
|
|
14
|
+
* what `sanitizeExtractUrl` does for URLs.
|
|
15
|
+
* - Extracted text passes `sanitizeExtractedText()` before entering turn
|
|
16
|
+
* context — the output-side analog: control characters stripped, newlines
|
|
17
|
+
* normalized, length capped.
|
|
18
|
+
*/
|
|
19
|
+
import type { ExtractOpts, ExtractProvider, ExtractResult } from '../types.js';
|
|
20
|
+
export { DocumentParseError } from './guards.js';
|
|
21
|
+
export type { DocumentParseErrorCode } from './guards.js';
|
|
22
|
+
export type { DocxExtractedText } from './docx.js';
|
|
23
|
+
export type { PdfCMap, PdfExtractedText } from './pdf.js';
|
|
24
|
+
export declare const PDF_MIME = "application/pdf";
|
|
25
|
+
export declare const DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
26
|
+
/** Document kinds this module can parse. */
|
|
27
|
+
export type SupportedDocumentKind = 'pdf' | 'docx';
|
|
28
|
+
export interface ParsedDocument {
|
|
29
|
+
readonly kind: SupportedDocumentKind;
|
|
30
|
+
readonly mimeType: string;
|
|
31
|
+
readonly text: string;
|
|
32
|
+
readonly title: string;
|
|
33
|
+
/** PDF only, best-effort. */
|
|
34
|
+
readonly pageCount?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Guess the document kind from a URL's path extension (query/fragment
|
|
38
|
+
* ignored). Used to decide whether a URL is worth fetching as a document;
|
|
39
|
+
* the magic-byte sniff always has the final say.
|
|
40
|
+
*/
|
|
41
|
+
export declare function detectDocumentKindFromUrl(url: string): SupportedDocumentKind | undefined;
|
|
42
|
+
/** Identify a document by magic bytes: `%PDF-` or the ZIP `PK\x03\x04`. */
|
|
43
|
+
export declare function sniffDocumentType(bytes: Uint8Array): SupportedDocumentKind | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Parse document `bytes` of the given MIME type. Throws
|
|
46
|
+
* {@link DocumentParseError} (`UNSUPPORTED_TYPE` / `DOCUMENT_TOO_LARGE` /
|
|
47
|
+
* `ARCHIVE_LIMIT` / `CORRUPT_DOCUMENT`) — never returns partial text.
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseDocument(bytes: Uint8Array, mimeType: string): Promise<ParsedDocument>;
|
|
50
|
+
/**
|
|
51
|
+
* Sanitize extracted text before it enters turn context — the output-side
|
|
52
|
+
* analog of `sanitizeExtractUrl`: strip control characters (log/terminal
|
|
53
|
+
* injection, model-input noise), normalize newlines, collapse blank runs,
|
|
54
|
+
* and cap length as defense-in-depth past the byte quotas.
|
|
55
|
+
*/
|
|
56
|
+
export declare function sanitizeExtractedText(text: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* Fetch `url`, sniff it, and parse it as a document — the entry point
|
|
59
|
+
* `ResearchOrchestrator.extract()` uses for `.pdf`/`.docx` URLs.
|
|
60
|
+
*
|
|
61
|
+
* - Magic bytes decide the parser (extension is only the trigger); a URL
|
|
62
|
+
* that merely LOOKS like a document but serves HTML falls back to the
|
|
63
|
+
* regular extract backend instead of failing.
|
|
64
|
+
* - A corrupt/oversize/bomb document throws `DocumentParseError` with a
|
|
65
|
+
* clear message (fail-closed — never silently handed to a third party).
|
|
66
|
+
* - Supports the same `offset` windowing as the other extract providers.
|
|
67
|
+
*/
|
|
68
|
+
export declare function extractDocument(url: string, extractProvider: ExtractProvider, signal?: AbortSignal, opts?: ExtractOpts): Promise<ExtractResult>;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `research.parse` — zero-dependency document parsing for research.
|
|
3
|
+
*
|
|
4
|
+
* `parseDocument(bytes, mimeType)` extracts text from PDF and DOCX without
|
|
5
|
+
* any npm dependency (only `node:zlib` for decompression, quota-guarded in
|
|
6
|
+
* `./guards.ts`). `extractDocument()` is the fetch-level entry the
|
|
7
|
+
* orchestrator calls: it downloads the URL with a hard byte cap, sniffs the
|
|
8
|
+
* magic bytes, and parses — or hands back to the regular extract backend
|
|
9
|
+
* when the bytes are not actually a document.
|
|
10
|
+
*
|
|
11
|
+
* Security posture (parse = attack surface):
|
|
12
|
+
* - Every input passes `./guards.ts` caps (file size, entry count, declared
|
|
13
|
+
* + actual decompression quotas) — the input-side choke point, mirroring
|
|
14
|
+
* what `sanitizeExtractUrl` does for URLs.
|
|
15
|
+
* - Extracted text passes `sanitizeExtractedText()` before entering turn
|
|
16
|
+
* context — the output-side analog: control characters stripped, newlines
|
|
17
|
+
* normalized, length capped.
|
|
18
|
+
*/
|
|
19
|
+
import { Buffer } from 'node:buffer';
|
|
20
|
+
import { DEFAULT_USER_AGENT, ResearchError, TRUNCATED_MARKER, } from '../http.js';
|
|
21
|
+
import { extractDocxText } from './docx.js';
|
|
22
|
+
import { DocumentParseError, MAX_DOCUMENT_BYTES, MAX_EXTRACTED_CHARS, assertDocumentSize, } from './guards.js';
|
|
23
|
+
import { extractPdfText } from './pdf.js';
|
|
24
|
+
export { DocumentParseError } from './guards.js';
|
|
25
|
+
export const PDF_MIME = 'application/pdf';
|
|
26
|
+
export const DOCX_MIME = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
27
|
+
/**
|
|
28
|
+
* Guess the document kind from a URL's path extension (query/fragment
|
|
29
|
+
* ignored). Used to decide whether a URL is worth fetching as a document;
|
|
30
|
+
* the magic-byte sniff always has the final say.
|
|
31
|
+
*/
|
|
32
|
+
export function detectDocumentKindFromUrl(url) {
|
|
33
|
+
const path = url.split(/[?#]/, 1)[0]?.toLowerCase() ?? '';
|
|
34
|
+
if (path.endsWith('.pdf'))
|
|
35
|
+
return 'pdf';
|
|
36
|
+
if (path.endsWith('.docx'))
|
|
37
|
+
return 'docx';
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
/** Identify a document by magic bytes: `%PDF-` or the ZIP `PK\x03\x04`. */
|
|
41
|
+
export function sniffDocumentType(bytes) {
|
|
42
|
+
if (bytes.length >= 5 &&
|
|
43
|
+
bytes[0] === 0x25 && // %
|
|
44
|
+
bytes[1] === 0x50 && // P
|
|
45
|
+
bytes[2] === 0x44 && // D
|
|
46
|
+
bytes[3] === 0x46 && // F
|
|
47
|
+
bytes[4] === 0x2d // -
|
|
48
|
+
) {
|
|
49
|
+
return 'pdf';
|
|
50
|
+
}
|
|
51
|
+
if (bytes.length >= 4 &&
|
|
52
|
+
bytes[0] === 0x50 && // P
|
|
53
|
+
bytes[1] === 0x4b && // K
|
|
54
|
+
bytes[2] === 0x03 &&
|
|
55
|
+
bytes[3] === 0x04) {
|
|
56
|
+
return 'docx';
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Parse document `bytes` of the given MIME type. Throws
|
|
62
|
+
* {@link DocumentParseError} (`UNSUPPORTED_TYPE` / `DOCUMENT_TOO_LARGE` /
|
|
63
|
+
* `ARCHIVE_LIMIT` / `CORRUPT_DOCUMENT`) — never returns partial text.
|
|
64
|
+
*/
|
|
65
|
+
export async function parseDocument(bytes, mimeType) {
|
|
66
|
+
assertDocumentSize(bytes.length);
|
|
67
|
+
const mime = mimeType.split(';', 1)[0]?.trim().toLowerCase() ?? '';
|
|
68
|
+
if (mime === PDF_MIME) {
|
|
69
|
+
const parsed = await extractPdfText(bytes);
|
|
70
|
+
return {
|
|
71
|
+
kind: 'pdf',
|
|
72
|
+
mimeType: PDF_MIME,
|
|
73
|
+
text: parsed.text,
|
|
74
|
+
title: parsed.title,
|
|
75
|
+
pageCount: parsed.pageCount,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (mime === DOCX_MIME) {
|
|
79
|
+
const parsed = await extractDocxText(bytes);
|
|
80
|
+
return {
|
|
81
|
+
kind: 'docx',
|
|
82
|
+
mimeType: DOCX_MIME,
|
|
83
|
+
text: parsed.text,
|
|
84
|
+
title: parsed.title,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
throw new DocumentParseError('UNSUPPORTED_TYPE', `Unsupported document type '${mimeType}'. Supported: ${PDF_MIME}, ${DOCX_MIME}.`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Sanitize extracted text before it enters turn context — the output-side
|
|
91
|
+
* analog of `sanitizeExtractUrl`: strip control characters (log/terminal
|
|
92
|
+
* injection, model-input noise), normalize newlines, collapse blank runs,
|
|
93
|
+
* and cap length as defense-in-depth past the byte quotas.
|
|
94
|
+
*/
|
|
95
|
+
export function sanitizeExtractedText(text) {
|
|
96
|
+
let out = '';
|
|
97
|
+
for (const ch of text) {
|
|
98
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
99
|
+
if (code === 0x0a || code === 0x09)
|
|
100
|
+
out += ch;
|
|
101
|
+
else if (code < 0x20 || code === 0x7f)
|
|
102
|
+
continue;
|
|
103
|
+
else
|
|
104
|
+
out += ch;
|
|
105
|
+
}
|
|
106
|
+
out = out
|
|
107
|
+
.replace(/\r\n?/g, '\n')
|
|
108
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
109
|
+
.trim();
|
|
110
|
+
if (out.length > MAX_EXTRACTED_CHARS)
|
|
111
|
+
out = out.slice(0, MAX_EXTRACTED_CHARS);
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
const FETCH_TIMEOUT_MS = 15_000;
|
|
115
|
+
/** Extract window, matching the jina provider's window for paging parity. */
|
|
116
|
+
const WINDOW_CHARS = 8000;
|
|
117
|
+
/**
|
|
118
|
+
* Fetch a URL as bytes with a hard cap — same streaming-cap pattern as
|
|
119
|
+
* `fetchText` in `../http.ts`, but returning bytes (a document is not text
|
|
120
|
+
* until parsed). Throws typed {@link ResearchError}s like the rest of the
|
|
121
|
+
* module.
|
|
122
|
+
*/
|
|
123
|
+
async function fetchBytes(url, opts) {
|
|
124
|
+
const timeoutSignal = AbortSignal.timeout(opts.timeoutMs);
|
|
125
|
+
const signal = opts.signal === undefined
|
|
126
|
+
? timeoutSignal
|
|
127
|
+
: AbortSignal.any([opts.signal, timeoutSignal]);
|
|
128
|
+
let response;
|
|
129
|
+
try {
|
|
130
|
+
response = await fetch(url, {
|
|
131
|
+
signal,
|
|
132
|
+
headers: { 'User-Agent': DEFAULT_USER_AGENT },
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
if (err instanceof DOMException && err.name === 'TimeoutError') {
|
|
137
|
+
throw new ResearchError('TIMEOUT', `Request to ${url} timed out`);
|
|
138
|
+
}
|
|
139
|
+
if (err instanceof DOMException && err.name === 'AbortError') {
|
|
140
|
+
throw new ResearchError('ABORTED', `Request to ${url} was aborted`);
|
|
141
|
+
}
|
|
142
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
143
|
+
throw new ResearchError('NETWORK_ERROR', `Network error fetching ${url}: ${detail}`);
|
|
144
|
+
}
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
const code = response.status >= 400 && response.status < 500 ? 'HTTP_4XX' : 'HTTP_5XX';
|
|
147
|
+
throw new ResearchError(code, `HTTP ${response.status} from ${url}`);
|
|
148
|
+
}
|
|
149
|
+
const body = response.body;
|
|
150
|
+
if (body === null)
|
|
151
|
+
return new Uint8Array(0);
|
|
152
|
+
const reader = body.getReader();
|
|
153
|
+
const chunks = [];
|
|
154
|
+
let total = 0;
|
|
155
|
+
for (;;) {
|
|
156
|
+
let read;
|
|
157
|
+
try {
|
|
158
|
+
read = await reader.read();
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
162
|
+
throw new ResearchError('NETWORK_ERROR', `Network error fetching ${url}: ${detail}`);
|
|
163
|
+
}
|
|
164
|
+
if (read.done)
|
|
165
|
+
break;
|
|
166
|
+
total += read.value.byteLength;
|
|
167
|
+
if (total > opts.maxBytes) {
|
|
168
|
+
await reader.cancel().catch(() => undefined);
|
|
169
|
+
throw new ResearchError('RESPONSE_TOO_LARGE', `Response from ${url} exceeds ${opts.maxBytes} bytes`);
|
|
170
|
+
}
|
|
171
|
+
chunks.push(read.value);
|
|
172
|
+
}
|
|
173
|
+
return Buffer.concat(chunks);
|
|
174
|
+
}
|
|
175
|
+
function firstLine(text) {
|
|
176
|
+
const line = text.split('\n', 1)[0]?.trim() ?? '';
|
|
177
|
+
return line.length > 120 ? `${line.slice(0, 120)}…` : line;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Fetch `url`, sniff it, and parse it as a document — the entry point
|
|
181
|
+
* `ResearchOrchestrator.extract()` uses for `.pdf`/`.docx` URLs.
|
|
182
|
+
*
|
|
183
|
+
* - Magic bytes decide the parser (extension is only the trigger); a URL
|
|
184
|
+
* that merely LOOKS like a document but serves HTML falls back to the
|
|
185
|
+
* regular extract backend instead of failing.
|
|
186
|
+
* - A corrupt/oversize/bomb document throws `DocumentParseError` with a
|
|
187
|
+
* clear message (fail-closed — never silently handed to a third party).
|
|
188
|
+
* - Supports the same `offset` windowing as the other extract providers.
|
|
189
|
+
*/
|
|
190
|
+
export async function extractDocument(url, extractProvider, signal, opts) {
|
|
191
|
+
const bytes = await fetchBytes(url, {
|
|
192
|
+
signal,
|
|
193
|
+
timeoutMs: FETCH_TIMEOUT_MS,
|
|
194
|
+
maxBytes: MAX_DOCUMENT_BYTES,
|
|
195
|
+
});
|
|
196
|
+
// Magic bytes decide the parser (the extension is only the trigger): a URL
|
|
197
|
+
// that merely LOOKS like a document but serves something else (e.g. an
|
|
198
|
+
// HTML error page) falls back to the regular extract backend instead of
|
|
199
|
+
// failing.
|
|
200
|
+
const kind = sniffDocumentType(bytes);
|
|
201
|
+
if (kind === undefined) {
|
|
202
|
+
return extractProvider.extract(url, signal, opts);
|
|
203
|
+
}
|
|
204
|
+
const parsed = await parseDocument(bytes, kind === 'pdf' ? PDF_MIME : DOCX_MIME);
|
|
205
|
+
const text = sanitizeExtractedText(parsed.text);
|
|
206
|
+
const offset = Math.max(0, Math.floor(opts?.offset ?? 0));
|
|
207
|
+
const slice = text.slice(offset, offset + WINDOW_CHARS);
|
|
208
|
+
const totalLength = text.length;
|
|
209
|
+
const hasMore = offset + slice.length < totalLength;
|
|
210
|
+
return {
|
|
211
|
+
url,
|
|
212
|
+
title: parsed.title !== '' ? parsed.title : firstLine(slice),
|
|
213
|
+
markdown: hasMore ? slice + TRUNCATED_MARKER : slice,
|
|
214
|
+
truncated: hasMore,
|
|
215
|
+
offset,
|
|
216
|
+
totalLength,
|
|
217
|
+
nextOffset: hasMore ? offset + WINDOW_CHARS : undefined,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal PDF text extractor — hand-written, zero npm dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Only `node:zlib` (via `./guards.ts` quotas) is used, for `/FlateDecode`
|
|
5
|
+
* content streams. This is a deliberate trade-off, documented honestly:
|
|
6
|
+
*
|
|
7
|
+
* - COVERED: text-based PDFs from common generators (FlateDecode or
|
|
8
|
+
* uncompressed content streams, `Tj`/`TJ`/`'`/`"` operators, literal and
|
|
9
|
+
* hex strings, WinAnsi/PDFDocEncoding bytes, UTF-16BE strings, and
|
|
10
|
+
* `/ToUnicode` CMaps — the subsetted-font encoding arXiv/LaTeX PDFs use).
|
|
11
|
+
* - NOT covered: encrypted PDFs (rejected), scanned/image-only PDFs (no OCR —
|
|
12
|
+
* text extraction correctly yields nothing), exotic filters (ASCII85,
|
|
13
|
+
* LZW, CCITT images are skipped), fonts with NEITHER a standard encoding
|
|
14
|
+
* NOR a ToUnicode map (byte values are emitted best-effort).
|
|
15
|
+
*
|
|
16
|
+
* A full renderer (pdf.js, poppler) would cover more, but both violate the
|
|
17
|
+
* project's zero-new-runtime-dep / easy-self-host philosophy — poppler is an
|
|
18
|
+
* OS package that may not exist on the host, pdf.js is megabytes of npm.
|
|
19
|
+
* For `research.extract`/`research.deep`, "most text out of most PDFs" is
|
|
20
|
+
* the right weight class.
|
|
21
|
+
*/
|
|
22
|
+
export interface PdfExtractedText {
|
|
23
|
+
readonly text: string;
|
|
24
|
+
readonly title: string;
|
|
25
|
+
/** Best-effort page count from `/Type /Page` objects; absent when undeterminable. */
|
|
26
|
+
readonly pageCount?: number;
|
|
27
|
+
}
|
|
28
|
+
/** A parsed `/ToUnicode` CMap: byte-group size + code → unicode char. */
|
|
29
|
+
export interface PdfCMap {
|
|
30
|
+
readonly bytesPerChar: number;
|
|
31
|
+
readonly map: ReadonlyMap<number, string>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Extract text from PDF `bytes`. Throws {@link DocumentParseError} with
|
|
35
|
+
* `CORRUPT_DOCUMENT` (not a PDF), `UNSUPPORTED_TYPE` (encrypted),
|
|
36
|
+
* `DOCUMENT_TOO_LARGE`, or `ARCHIVE_LIMIT` (stream bomb).
|
|
37
|
+
*/
|
|
38
|
+
export declare function extractPdfText(bytes: Uint8Array): Promise<PdfExtractedText>;
|