@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,567 @@
|
|
|
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
|
+
import { Buffer } from 'node:buffer';
|
|
23
|
+
import { DecompressionQuota, DocumentParseError, MAX_PDF_STREAMS, MAX_ZIP_ENTRY_BYTES, assertDocumentSize, } from './guards.js';
|
|
24
|
+
/** Windows-1252-ish byte → char mapping (covers PDFDocEncoding's printable range). */
|
|
25
|
+
const BYTE_TO_CHAR = (() => {
|
|
26
|
+
const win1252 = {
|
|
27
|
+
0x80: 0x20ac, 0x82: 0x201a, 0x83: 0x0192, 0x84: 0x201e, 0x85: 0x2026,
|
|
28
|
+
0x86: 0x2020, 0x87: 0x2021, 0x88: 0x02c6, 0x89: 0x2030, 0x8a: 0x0160,
|
|
29
|
+
0x8b: 0x2039, 0x8c: 0x0152, 0x8e: 0x017d, 0x91: 0x2018, 0x92: 0x2019,
|
|
30
|
+
0x93: 0x201c, 0x94: 0x201d, 0x95: 0x2022, 0x96: 0x2013, 0x97: 0x2014,
|
|
31
|
+
0x98: 0x02dc, 0x99: 0x2122, 0x9a: 0x0161, 0x9b: 0x203a, 0x9c: 0x0153,
|
|
32
|
+
0x9e: 0x017e, 0x9f: 0x0178,
|
|
33
|
+
};
|
|
34
|
+
const table = new Array(256);
|
|
35
|
+
for (let b = 0; b < 256; b += 1) {
|
|
36
|
+
if (b < 0x80)
|
|
37
|
+
table[b] = String.fromCharCode(b);
|
|
38
|
+
else if (win1252[b] !== undefined)
|
|
39
|
+
table[b] = String.fromCodePoint(win1252[b]);
|
|
40
|
+
else
|
|
41
|
+
table[b] = String.fromCharCode(b);
|
|
42
|
+
}
|
|
43
|
+
return table;
|
|
44
|
+
})();
|
|
45
|
+
/** Decode one PDF string's raw bytes: UTF-16BE when BOM'd, else byte-mapped. */
|
|
46
|
+
function decodePdfBytes(raw) {
|
|
47
|
+
if (raw.length >= 2 && raw[0] === 0xfe && raw[1] === 0xff) {
|
|
48
|
+
let out = '';
|
|
49
|
+
for (let i = 2; i + 1 < raw.length; i += 2) {
|
|
50
|
+
const hi = raw[i] ?? 0;
|
|
51
|
+
const lo = raw[i + 1] ?? 0;
|
|
52
|
+
const code = (hi << 8) | lo;
|
|
53
|
+
// Skip a BOM re-appearing mid-string; lone surrogates are dropped
|
|
54
|
+
// rather than emitted as mojibake.
|
|
55
|
+
if (code === 0xfeff)
|
|
56
|
+
continue;
|
|
57
|
+
out += String.fromCharCode(code);
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
let out = '';
|
|
62
|
+
for (const b of raw)
|
|
63
|
+
out += BYTE_TO_CHAR[b] ?? '';
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
/** Decode a CMap destination hex string (UTF-16BE code units). */
|
|
67
|
+
function decodeUtf16Hex(hex) {
|
|
68
|
+
let out = '';
|
|
69
|
+
for (let i = 0; i + 4 <= hex.length; i += 4) {
|
|
70
|
+
out += String.fromCharCode(parseInt(hex.slice(i, i + 4), 16));
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A regex group that is present by construction (the match could not have
|
|
76
|
+
* succeeded without it). Throws rather than threading `| undefined`
|
|
77
|
+
* through every CMap call site.
|
|
78
|
+
*/
|
|
79
|
+
function grp(m, i) {
|
|
80
|
+
const v = m[i];
|
|
81
|
+
if (v === undefined)
|
|
82
|
+
throw new Error(`CMap match missing group ${i}`);
|
|
83
|
+
return v;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Parse a `begincmap ... endcmap` stream: `beginbfchar` pairs and
|
|
87
|
+
* `beginbfrange` ranges (both the `<dst>` and `[<dst> ...]` forms).
|
|
88
|
+
* Anything unrecognized is skipped — a partial map beats no map.
|
|
89
|
+
*/
|
|
90
|
+
function parseCMap(cmapText) {
|
|
91
|
+
let bytesPerChar = 1;
|
|
92
|
+
const rangeBlock = /begincodespacerange([\s\S]*?)endcodespacerange/.exec(cmapText);
|
|
93
|
+
if (rangeBlock !== null) {
|
|
94
|
+
let longest = 0;
|
|
95
|
+
for (const m of grp(rangeBlock, 1).matchAll(/<([0-9a-fA-F]+)>/g)) {
|
|
96
|
+
longest = Math.max(longest, grp(m, 1).length / 2);
|
|
97
|
+
}
|
|
98
|
+
if (longest > 0)
|
|
99
|
+
bytesPerChar = Math.min(longest, 2);
|
|
100
|
+
}
|
|
101
|
+
const map = new Map();
|
|
102
|
+
for (const block of cmapText.matchAll(/beginbfchar([\s\S]*?)endbfchar/g)) {
|
|
103
|
+
for (const p of grp(block, 1).matchAll(/<([0-9a-fA-F]+)>\s*<([0-9a-fA-F]+)>/g)) {
|
|
104
|
+
map.set(parseInt(grp(p, 1), 16), decodeUtf16Hex(grp(p, 2)));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const block of cmapText.matchAll(/beginbfrange([\s\S]*?)endbfrange/g)) {
|
|
108
|
+
for (const t of grp(block, 1).matchAll(/<([0-9a-fA-F]+)>\s*<([0-9a-fA-F]+)>\s*(?:<([0-9a-fA-F]+)>|\[([^\]]*)\])/g)) {
|
|
109
|
+
const lo = parseInt(grp(t, 1), 16);
|
|
110
|
+
const hi = parseInt(grp(t, 2), 16);
|
|
111
|
+
// A hostile or sloppy CMap could declare a gigantic range; cap it.
|
|
112
|
+
const end = Math.min(hi, lo + 65535);
|
|
113
|
+
if (t[3] !== undefined) {
|
|
114
|
+
const dstLo = parseInt(grp(t, 3), 16);
|
|
115
|
+
for (let c = lo; c <= end; c += 1) {
|
|
116
|
+
map.set(c, String.fromCodePoint(dstLo + (c - lo)));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (t[4] !== undefined) {
|
|
120
|
+
const dsts = [...grp(t, 4).matchAll(/<([0-9a-fA-F]+)>/g)].map((m) => decodeUtf16Hex(grp(m, 1)));
|
|
121
|
+
for (let c = lo; c <= end && c - lo < dsts.length; c += 1) {
|
|
122
|
+
const dst = dsts[c - lo];
|
|
123
|
+
if (dst !== undefined)
|
|
124
|
+
map.set(c, dst);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { bytesPerChar, map };
|
|
130
|
+
}
|
|
131
|
+
/** Map indirect object numbers to their bodies (on stream-stripped text). */
|
|
132
|
+
function buildObjectMap(stripped) {
|
|
133
|
+
const map = new Map();
|
|
134
|
+
const re = /(\d+)\s+0\s+obj([\s\S]*?)endobj/g;
|
|
135
|
+
for (;;) {
|
|
136
|
+
const m = re.exec(stripped);
|
|
137
|
+
if (m === null)
|
|
138
|
+
break;
|
|
139
|
+
map.set(parseInt(grp(m, 1), 10), grp(m, 2));
|
|
140
|
+
}
|
|
141
|
+
return map;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Resolve font resource names (`F1`) to their `/ToUnicode` CMaps by walking
|
|
145
|
+
* `/Resources → /Font → font object → /ToUnicode`. `cmapTexts` carries the
|
|
146
|
+
* already-inflated CMap streams keyed by object number (collected by
|
|
147
|
+
* `extractStreams`). Best-effort throughout: a PDF without this structure
|
|
148
|
+
* simply yields an empty map and falls back to byte decoding.
|
|
149
|
+
*/
|
|
150
|
+
function buildFontCMaps(stripped, cmapTexts) {
|
|
151
|
+
const out = new Map();
|
|
152
|
+
try {
|
|
153
|
+
const objMap = buildObjectMap(stripped);
|
|
154
|
+
const fontToUnicode = new Map();
|
|
155
|
+
for (const [num, body] of objMap) {
|
|
156
|
+
const t = /\/ToUnicode\s+(\d+)\s+0\s+R/.exec(body);
|
|
157
|
+
if (t !== null)
|
|
158
|
+
fontToUnicode.set(num, parseInt(grp(t, 1), 10));
|
|
159
|
+
}
|
|
160
|
+
if (fontToUnicode.size === 0)
|
|
161
|
+
return out;
|
|
162
|
+
// Font resource names (`F1` in `/F1 12 Tf`): for each font object, find
|
|
163
|
+
// every `/Name <fontObj> 0 R` reference sitting inside a `<<...>>` dict.
|
|
164
|
+
// This covers both inline `/Resources << /Font << /F1 9 0 R >> >>` and
|
|
165
|
+
// the common indirection where the name→object dict lives in its own
|
|
166
|
+
// object (`11 0 obj << /F1 9 0 R >>`). A stray match (e.g. `/Parent`)
|
|
167
|
+
// is harmless: the map is only consulted for names seen before `Tf`.
|
|
168
|
+
const nameToFont = new Map();
|
|
169
|
+
for (const fontNum of fontToUnicode.keys()) {
|
|
170
|
+
const refRe = new RegExp(`/([A-Za-z0-9_+\\-.]+)\\s+${fontNum}\\s+0\\s+R`, 'g');
|
|
171
|
+
for (const m of stripped.matchAll(refRe)) {
|
|
172
|
+
const open = stripped.lastIndexOf('<<', m.index);
|
|
173
|
+
if (open < 0)
|
|
174
|
+
continue;
|
|
175
|
+
if (stripped.slice(open, m.index).includes('>>'))
|
|
176
|
+
continue;
|
|
177
|
+
nameToFont.set(grp(m, 1), fontNum);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const [name, fontNum] of nameToFont) {
|
|
181
|
+
const uniNum = fontToUnicode.get(fontNum);
|
|
182
|
+
if (uniNum === undefined)
|
|
183
|
+
continue;
|
|
184
|
+
const cmapText = cmapTexts.get(uniNum);
|
|
185
|
+
if (cmapText === undefined)
|
|
186
|
+
continue;
|
|
187
|
+
try {
|
|
188
|
+
out.set(name, parseCMap(cmapText));
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// A broken CMap must not fail the document.
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// CMap resolution is best-effort; byte decoding remains.
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Extract the text-showing operations of one content stream.
|
|
202
|
+
* Handles `(literal) Tj`, `<hex> Tj`, `[...] TJ`, `'...'` and `"..."`.
|
|
203
|
+
* `cmaps` maps PDF font resource names (`F1` in `/F1 12 Tf`) to their
|
|
204
|
+
* `/ToUnicode` CMaps; strings set in a mapped font are decoded through it.
|
|
205
|
+
*/
|
|
206
|
+
function extractContentText(content, cmaps) {
|
|
207
|
+
const parts = [];
|
|
208
|
+
let i = 0;
|
|
209
|
+
const n = content.length;
|
|
210
|
+
let currentFont;
|
|
211
|
+
const skipWs = () => {
|
|
212
|
+
while (i < n) {
|
|
213
|
+
const c = content[i];
|
|
214
|
+
if (c === ' ' || c === '\t' || c === '\n' || c === '\r' || c === '\f' || c === '\0')
|
|
215
|
+
i += 1;
|
|
216
|
+
else
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
/** Read an operator token at the current position (after whitespace). */
|
|
221
|
+
const readOperator = () => {
|
|
222
|
+
skipWs();
|
|
223
|
+
const start = i;
|
|
224
|
+
while (i < n) {
|
|
225
|
+
const c = content[i] ?? '';
|
|
226
|
+
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c === "'" || c === '"' || c === '*')
|
|
227
|
+
i += 1;
|
|
228
|
+
else
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
return content.slice(start, i);
|
|
232
|
+
};
|
|
233
|
+
/** Parse a balanced literal string; `i` points at `(`. Returns raw bytes. */
|
|
234
|
+
const readLiteral = () => {
|
|
235
|
+
i += 1; // '('
|
|
236
|
+
const bytes = [];
|
|
237
|
+
let depth = 1;
|
|
238
|
+
while (i < n && depth > 0) {
|
|
239
|
+
const c = content[i] ?? '';
|
|
240
|
+
if (c === '\\') {
|
|
241
|
+
const e = content[i + 1];
|
|
242
|
+
i += 2;
|
|
243
|
+
if (e === undefined)
|
|
244
|
+
break;
|
|
245
|
+
if (e === 'n')
|
|
246
|
+
bytes.push(0x0a);
|
|
247
|
+
else if (e === 'r')
|
|
248
|
+
bytes.push(0x0d);
|
|
249
|
+
else if (e === 't')
|
|
250
|
+
bytes.push(0x09);
|
|
251
|
+
else if (e === 'b')
|
|
252
|
+
bytes.push(0x08);
|
|
253
|
+
else if (e === 'f')
|
|
254
|
+
bytes.push(0x0c);
|
|
255
|
+
else if (e === '(')
|
|
256
|
+
bytes.push(0x28);
|
|
257
|
+
else if (e === ')')
|
|
258
|
+
bytes.push(0x29);
|
|
259
|
+
else if (e === '\\')
|
|
260
|
+
bytes.push(0x5c);
|
|
261
|
+
else if (e === '\n') { /* line continuation — nothing */ }
|
|
262
|
+
else if (e === '\r') {
|
|
263
|
+
if (content[i] === '\n')
|
|
264
|
+
i += 1;
|
|
265
|
+
}
|
|
266
|
+
else if (e >= '0' && e <= '7') {
|
|
267
|
+
let oct = e;
|
|
268
|
+
for (let k = 0; k < 2; k += 1) {
|
|
269
|
+
const d = content[i];
|
|
270
|
+
if (d !== undefined && d >= '0' && d <= '7') {
|
|
271
|
+
oct += d;
|
|
272
|
+
i += 1;
|
|
273
|
+
}
|
|
274
|
+
else
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
bytes.push(parseInt(oct, 8) & 0xff);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
bytes.push(e.charCodeAt(0) & 0xff);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else if (c === '(') {
|
|
284
|
+
depth += 1;
|
|
285
|
+
bytes.push(0x28);
|
|
286
|
+
i += 1;
|
|
287
|
+
}
|
|
288
|
+
else if (c === ')') {
|
|
289
|
+
depth -= 1;
|
|
290
|
+
if (depth > 0)
|
|
291
|
+
bytes.push(0x29);
|
|
292
|
+
i += 1;
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
bytes.push(c.charCodeAt(0) & 0xff);
|
|
296
|
+
i += 1;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return Uint8Array.from(bytes);
|
|
300
|
+
};
|
|
301
|
+
/** Parse a hex string; `i` points at `<` (not `<<`). */
|
|
302
|
+
const readHex = () => {
|
|
303
|
+
i += 1; // '<'
|
|
304
|
+
let hex = '';
|
|
305
|
+
while (i < n && content[i] !== '>') {
|
|
306
|
+
const c = content[i] ?? '';
|
|
307
|
+
if (c !== ' ' && c !== '\t' && c !== '\n' && c !== '\r' && c !== '\f')
|
|
308
|
+
hex += c;
|
|
309
|
+
i += 1;
|
|
310
|
+
}
|
|
311
|
+
i += 1; // '>'
|
|
312
|
+
if (hex.length % 2 === 1)
|
|
313
|
+
hex += '0';
|
|
314
|
+
const out = new Uint8Array(hex.length / 2);
|
|
315
|
+
for (let k = 0; k < out.length; k += 1) {
|
|
316
|
+
out[k] = parseInt(hex.slice(k * 2, k * 2 + 2), 16);
|
|
317
|
+
}
|
|
318
|
+
return out;
|
|
319
|
+
};
|
|
320
|
+
/** Decode one string's bytes: the current font's ToUnicode CMap wins, else byte mapping. */
|
|
321
|
+
const decodeString = (raw) => {
|
|
322
|
+
const cmap = currentFont !== undefined ? cmaps.get(currentFont) : undefined;
|
|
323
|
+
if (cmap === undefined)
|
|
324
|
+
return decodePdfBytes(raw);
|
|
325
|
+
let out = '';
|
|
326
|
+
const step = cmap.bytesPerChar;
|
|
327
|
+
for (let k = 0; k < raw.length; k += step) {
|
|
328
|
+
let code = 0;
|
|
329
|
+
for (let b = 0; b < step && k + b < raw.length; b += 1) {
|
|
330
|
+
code = (code << 8) | (raw[k + b] ?? 0);
|
|
331
|
+
}
|
|
332
|
+
out += cmap.map.get(code) ?? decodePdfBytes(raw.slice(k, k + step));
|
|
333
|
+
}
|
|
334
|
+
return out;
|
|
335
|
+
};
|
|
336
|
+
while (i < n) {
|
|
337
|
+
skipWs();
|
|
338
|
+
if (i >= n)
|
|
339
|
+
break;
|
|
340
|
+
const c = content[i] ?? '';
|
|
341
|
+
if (c === '/') {
|
|
342
|
+
// Possible `/F1 12 Tf` — track the current font for ToUnicode decoding.
|
|
343
|
+
const nameMatch = /^\/([A-Za-z0-9_+\-.]+)/.exec(content.slice(i));
|
|
344
|
+
if (nameMatch !== null) {
|
|
345
|
+
const afterName = i + nameMatch[0].length;
|
|
346
|
+
const tfMatch = /^\s*\d+(?:\.\d+)?\s+Tf\b/.exec(content.slice(afterName));
|
|
347
|
+
if (tfMatch !== null) {
|
|
348
|
+
currentFont = nameMatch[1];
|
|
349
|
+
i = afterName + tfMatch[0].length;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
i += 1;
|
|
354
|
+
}
|
|
355
|
+
else if (c === '(') {
|
|
356
|
+
const raw = readLiteral();
|
|
357
|
+
const op = readOperator();
|
|
358
|
+
if (op === 'Tj')
|
|
359
|
+
parts.push(decodeString(raw));
|
|
360
|
+
else if (op === "'") {
|
|
361
|
+
// ' = T* + Tj: next line of text.
|
|
362
|
+
parts.push(decodeString(raw));
|
|
363
|
+
parts.push('\n');
|
|
364
|
+
}
|
|
365
|
+
else if (op === '"') {
|
|
366
|
+
// " = Tw Tc + ': operands (aw ac) precede the string.
|
|
367
|
+
parts.push(decodeString(raw));
|
|
368
|
+
parts.push('\n');
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
else if (c === '<' && content[i + 1] !== '<') {
|
|
372
|
+
const raw = readHex();
|
|
373
|
+
const op = readOperator();
|
|
374
|
+
if (op === 'Tj')
|
|
375
|
+
parts.push(decodeString(raw));
|
|
376
|
+
}
|
|
377
|
+
else if (c === '[') {
|
|
378
|
+
i += 1; // '['
|
|
379
|
+
const items = [];
|
|
380
|
+
for (;;) {
|
|
381
|
+
skipWs();
|
|
382
|
+
if (i >= n)
|
|
383
|
+
break;
|
|
384
|
+
const t = content[i] ?? '';
|
|
385
|
+
if (t === ']') {
|
|
386
|
+
i += 1;
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
if (t === '(')
|
|
390
|
+
items.push(decodeString(readLiteral()));
|
|
391
|
+
else if (t === '<' && content[i + 1] !== '<')
|
|
392
|
+
items.push(decodeString(readHex()));
|
|
393
|
+
else
|
|
394
|
+
i += 1; // kerning numbers and anything else
|
|
395
|
+
}
|
|
396
|
+
if (readOperator() === 'TJ')
|
|
397
|
+
parts.push(items.join(' '));
|
|
398
|
+
}
|
|
399
|
+
else if (c === 'T' && content[i + 1] === '*') {
|
|
400
|
+
i += 2;
|
|
401
|
+
parts.push('\n');
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
i += 1;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return parts.join(' ').replace(/ \n /g, '\n').replace(/ \n/g, '\n');
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Inflate FlateDecode content streams (quota-guarded); pass through
|
|
411
|
+
* unfiltered streams; skip anything else (images, exotic filters).
|
|
412
|
+
* One corrupt stream never kills the document — it is skipped.
|
|
413
|
+
*
|
|
414
|
+
* `/ToUnicode` CMap streams are inflated here too (they are just streams);
|
|
415
|
+
* `extractPdfText` separates them by content (`begincmap`) afterwards.
|
|
416
|
+
*/
|
|
417
|
+
async function extractStreams(bytes, quota) {
|
|
418
|
+
const latin = Buffer.from(bytes).toString('latin1');
|
|
419
|
+
const out = [];
|
|
420
|
+
const re = /stream\r?\n([\s\S]*?)\r?\nendstream/g;
|
|
421
|
+
let count = 0;
|
|
422
|
+
for (;;) {
|
|
423
|
+
const m = re.exec(latin);
|
|
424
|
+
if (m === null)
|
|
425
|
+
break;
|
|
426
|
+
count += 1;
|
|
427
|
+
if (count > MAX_PDF_STREAMS) {
|
|
428
|
+
throw new DocumentParseError('ARCHIVE_LIMIT', `PDF declares more than ${MAX_PDF_STREAMS} content streams.`);
|
|
429
|
+
}
|
|
430
|
+
// The stream's owner is the last `N 0 obj` header before it
|
|
431
|
+
// (objects never nest, so the nearest header owns the stream).
|
|
432
|
+
const before = latin.slice(Math.max(0, m.index - 4000), m.index);
|
|
433
|
+
let objNum;
|
|
434
|
+
for (const om of before.matchAll(/(\d+)\s+0\s+obj/g)) {
|
|
435
|
+
objNum = parseInt(grp(om, 1), 10);
|
|
436
|
+
}
|
|
437
|
+
// Look at the stream's own dictionary only: the nearest `<<` before
|
|
438
|
+
// `stream`, so a previous object's /Filter can't mislabel this one.
|
|
439
|
+
const dictOpen = latin.lastIndexOf('<<', m.index);
|
|
440
|
+
const dictText = dictOpen >= 0 && m.index - dictOpen < 4000
|
|
441
|
+
? latin.slice(dictOpen, m.index)
|
|
442
|
+
: '';
|
|
443
|
+
const filterMatch = /\/Filter\s*(\[[^\]]*\]|\/[A-Za-z0-9]+)/.exec(dictText);
|
|
444
|
+
const filterText = filterMatch !== null ? grp(filterMatch, 1) : '';
|
|
445
|
+
try {
|
|
446
|
+
if (filterText.includes('FlateDecode')) {
|
|
447
|
+
const raw = Buffer.from(m[1] ?? '', 'latin1');
|
|
448
|
+
// PDF FlateDecode is zlib-wrapped (RFC 1950), not raw deflate.
|
|
449
|
+
const inflated = await quota.inflate(raw, MAX_ZIP_ENTRY_BYTES, `pdf-stream#${count}`);
|
|
450
|
+
out.push({ text: Buffer.from(inflated).toString('latin1'), objNum });
|
|
451
|
+
}
|
|
452
|
+
else if (filterText === '') {
|
|
453
|
+
out.push({ text: m[1] ?? '', objNum });
|
|
454
|
+
}
|
|
455
|
+
// else: image/exotic filter — skipped, not text.
|
|
456
|
+
}
|
|
457
|
+
catch {
|
|
458
|
+
// One bad stream is skipped; the document still parses.
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return out;
|
|
462
|
+
}
|
|
463
|
+
/** Best-effort `/Title (...)` lookup on stream-stripped text. */
|
|
464
|
+
function findInfoString(stripped, key) {
|
|
465
|
+
const at = stripped.indexOf(`/${key}`);
|
|
466
|
+
if (at < 0)
|
|
467
|
+
return undefined;
|
|
468
|
+
let i = at + key.length + 1;
|
|
469
|
+
while (i < stripped.length && /\s/.test(stripped[i] ?? ''))
|
|
470
|
+
i += 1;
|
|
471
|
+
if (stripped[i] !== '(')
|
|
472
|
+
return undefined;
|
|
473
|
+
i += 1;
|
|
474
|
+
const bytes = [];
|
|
475
|
+
let depth = 1;
|
|
476
|
+
while (i < stripped.length && depth > 0) {
|
|
477
|
+
const c = stripped[i] ?? '';
|
|
478
|
+
if (c === '\\') {
|
|
479
|
+
const e = stripped[i + 1] ?? '';
|
|
480
|
+
bytes.push(e.charCodeAt(0) & 0xff);
|
|
481
|
+
i += 2;
|
|
482
|
+
}
|
|
483
|
+
else if (c === '(') {
|
|
484
|
+
depth += 1;
|
|
485
|
+
bytes.push(0x28);
|
|
486
|
+
i += 1;
|
|
487
|
+
}
|
|
488
|
+
else if (c === ')') {
|
|
489
|
+
depth -= 1;
|
|
490
|
+
if (depth > 0)
|
|
491
|
+
bytes.push(0x29);
|
|
492
|
+
i += 1;
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
bytes.push(c.charCodeAt(0) & 0xff);
|
|
496
|
+
i += 1;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (depth !== 0)
|
|
500
|
+
return undefined;
|
|
501
|
+
return decodePdfBytes(Uint8Array.from(bytes));
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Extract text from PDF `bytes`. Throws {@link DocumentParseError} with
|
|
505
|
+
* `CORRUPT_DOCUMENT` (not a PDF), `UNSUPPORTED_TYPE` (encrypted),
|
|
506
|
+
* `DOCUMENT_TOO_LARGE`, or `ARCHIVE_LIMIT` (stream bomb).
|
|
507
|
+
*/
|
|
508
|
+
export async function extractPdfText(bytes) {
|
|
509
|
+
assertDocumentSize(bytes.length, 'PDF');
|
|
510
|
+
// Skip a UTF-8 BOM and leading whitespace before the header.
|
|
511
|
+
let p = 0;
|
|
512
|
+
while (p < bytes.length) {
|
|
513
|
+
const b = bytes[p] ?? 0;
|
|
514
|
+
if (b === 0x20 || b === 0x09 || b === 0x0a || b === 0x0d)
|
|
515
|
+
p += 1;
|
|
516
|
+
else if (b === 0xef && bytes[p + 1] === 0xbb && bytes[p + 2] === 0xbf)
|
|
517
|
+
p += 3;
|
|
518
|
+
else
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
const magic = [0x25, 0x50, 0x44, 0x46, 0x2d]; // '%PDF-'
|
|
522
|
+
for (let k = 0; k < magic.length; k += 1) {
|
|
523
|
+
if (bytes[p + k] !== magic[k]) {
|
|
524
|
+
throw new DocumentParseError('CORRUPT_DOCUMENT', 'Not a PDF file (missing %PDF- header).');
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
const latin = Buffer.from(bytes).toString('latin1');
|
|
528
|
+
// Scan for /Encrypt outside content streams — inside a stream the token
|
|
529
|
+
// could be literal page text, which must not false-positive.
|
|
530
|
+
const stripped = latin.replace(/stream\r?\n[\s\S]*?\r?\nendstream/g, '');
|
|
531
|
+
if (/\/Encrypt\b/.test(stripped)) {
|
|
532
|
+
throw new DocumentParseError('UNSUPPORTED_TYPE', 'Encrypted PDFs are not supported.');
|
|
533
|
+
}
|
|
534
|
+
const quota = new DecompressionQuota();
|
|
535
|
+
const streams = await extractStreams(bytes, quota);
|
|
536
|
+
// Separate /ToUnicode CMap streams from content streams by content.
|
|
537
|
+
const cmapTexts = new Map();
|
|
538
|
+
const contentTexts = [];
|
|
539
|
+
for (const s of streams) {
|
|
540
|
+
if (s.objNum !== undefined &&
|
|
541
|
+
s.text.includes('begincmap') &&
|
|
542
|
+
s.text.includes('endcmap')) {
|
|
543
|
+
cmapTexts.set(s.objNum, s.text);
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
contentTexts.push(s.text);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
// Resolve /ToUnicode CMaps before extracting text (best-effort; a
|
|
550
|
+
// failure here only loses the mapping, never the document).
|
|
551
|
+
const cmaps = buildFontCMaps(stripped, cmapTexts);
|
|
552
|
+
if (contentTexts.length === 0) {
|
|
553
|
+
// A header alone is not a document: image-only PDFs still carry
|
|
554
|
+
// (image) streams, so zero content streams means this is not a real PDF.
|
|
555
|
+
throw new DocumentParseError('CORRUPT_DOCUMENT', 'PDF has no content streams.');
|
|
556
|
+
}
|
|
557
|
+
const texts = contentTexts
|
|
558
|
+
.map((s) => extractContentText(s, cmaps).trim())
|
|
559
|
+
.filter((t) => t !== '');
|
|
560
|
+
const title = findInfoString(stripped, 'Title') ?? '';
|
|
561
|
+
const pageMatches = stripped.match(/\/Type\s*\/Page(?![A-Za-z])/g);
|
|
562
|
+
return {
|
|
563
|
+
text: texts.join('\n\n'),
|
|
564
|
+
title,
|
|
565
|
+
pageCount: pageMatches !== null ? pageMatches.length : undefined,
|
|
566
|
+
};
|
|
567
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* arXiv search provider (free, no key).
|
|
3
|
+
*
|
|
4
|
+
* Uses the arXiv OAI-style query API (`export.arxiv.org/api/query`).
|
|
5
|
+
* The XML response is parsed with a small purpose-built parser — no XML
|
|
6
|
+
* dependency, no DOM. HTML entities in text nodes are decoded.
|
|
7
|
+
*/
|
|
8
|
+
import type { ResearchProvider } from '../types.js';
|
|
9
|
+
export declare function createArxivProvider(): ResearchProvider;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* arXiv search provider (free, no key).
|
|
3
|
+
*
|
|
4
|
+
* Uses the arXiv OAI-style query API (`export.arxiv.org/api/query`).
|
|
5
|
+
* The XML response is parsed with a small purpose-built parser — no XML
|
|
6
|
+
* dependency, no DOM. HTML entities in text nodes are decoded.
|
|
7
|
+
*/
|
|
8
|
+
import { fetchText, truncate, withRetry } from '../http.js';
|
|
9
|
+
const MAX_RESULTS = 20;
|
|
10
|
+
function decodeEntities(text) {
|
|
11
|
+
return text
|
|
12
|
+
.replace(/&/g, '&')
|
|
13
|
+
.replace(/</g, '<')
|
|
14
|
+
.replace(/>/g, '>')
|
|
15
|
+
.replace(/"/g, '"')
|
|
16
|
+
.replace(/'/g, "'")
|
|
17
|
+
.replace(/'/g, "'");
|
|
18
|
+
}
|
|
19
|
+
function collapseWhitespace(text) {
|
|
20
|
+
return decodeEntities(text).replace(/\s+/g, ' ').trim();
|
|
21
|
+
}
|
|
22
|
+
/** Extract the text of the first `<tag>…</tag>` block inside `xml`. */
|
|
23
|
+
function tagText(xml, tag) {
|
|
24
|
+
const re = new RegExp(`<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${tag}>`);
|
|
25
|
+
const match = re.exec(xml);
|
|
26
|
+
return match?.[1] === undefined ? undefined : collapseWhitespace(match[1]);
|
|
27
|
+
}
|
|
28
|
+
function parseEntries(xml) {
|
|
29
|
+
const entries = [];
|
|
30
|
+
const entryRe = /<entry>([\s\S]*?)<\/entry>/g;
|
|
31
|
+
for (const match of xml.matchAll(entryRe)) {
|
|
32
|
+
const body = match[1] ?? '';
|
|
33
|
+
const title = tagText(body, 'title');
|
|
34
|
+
const id = tagText(body, 'id');
|
|
35
|
+
if (title === undefined || id === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
entries.push({
|
|
38
|
+
title,
|
|
39
|
+
id,
|
|
40
|
+
summary: tagText(body, 'summary') ?? '',
|
|
41
|
+
published: tagText(body, 'published'),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return entries;
|
|
45
|
+
}
|
|
46
|
+
export function createArxivProvider() {
|
|
47
|
+
return {
|
|
48
|
+
id: 'arxiv',
|
|
49
|
+
kind: 'free',
|
|
50
|
+
async search(query, opts = {}) {
|
|
51
|
+
const limit = Math.min(Math.max(opts.limit ?? 8, 1), MAX_RESULTS);
|
|
52
|
+
const params = new URLSearchParams({
|
|
53
|
+
search_query: `all:${query}`,
|
|
54
|
+
start: '0',
|
|
55
|
+
max_results: String(limit),
|
|
56
|
+
sortBy: 'relevance',
|
|
57
|
+
sortOrder: 'descending',
|
|
58
|
+
});
|
|
59
|
+
const url = `https://export.arxiv.org/api/query?${params.toString()}`;
|
|
60
|
+
const xml = await withRetry(() => fetchText(url, { signal: opts.signal, timeoutMs: 15_000 }));
|
|
61
|
+
return parseEntries(xml)
|
|
62
|
+
.slice(0, limit)
|
|
63
|
+
.map((entry) => ({
|
|
64
|
+
title: entry.title,
|
|
65
|
+
url: entry.id.replace('http://', 'https://'),
|
|
66
|
+
snippet: truncate(entry.summary, 300),
|
|
67
|
+
source: 'arxiv',
|
|
68
|
+
publishedAt: entry.published,
|
|
69
|
+
}));
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brave Search adapter (paid, API key required).
|
|
3
|
+
*
|
|
4
|
+
* Wraps the Brave Search API (`/res/v1/web/search`). The key travels in
|
|
5
|
+
* the `X-Subscription-Token` header — never in the URL, never logged.
|
|
6
|
+
*/
|
|
7
|
+
import type { ResearchProvider } from '../types.js';
|
|
8
|
+
export interface BraveProviderOptions {
|
|
9
|
+
readonly apiKey: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function createBraveProvider(options: BraveProviderOptions): ResearchProvider;
|