dotdo 0.0.1 → 0.0.2
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/LICENSE +1 -1
- package/README.md +446 -315
- package/dist/ai/index.js +19 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/template-literals.js +852 -0
- package/dist/ai/template-literals.js.map +1 -0
- package/dist/api/analytics/router.js +601 -0
- package/dist/api/analytics/router.js.map +1 -0
- package/dist/api/index.js +158 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/middleware/auth-federation.js +573 -0
- package/dist/api/middleware/auth-federation.js.map +1 -0
- package/dist/api/middleware/auth.js +544 -0
- package/dist/api/middleware/auth.js.map +1 -0
- package/dist/api/middleware/error-handling.js +176 -0
- package/dist/api/middleware/error-handling.js.map +1 -0
- package/dist/api/middleware/request-id.js +21 -0
- package/dist/api/middleware/request-id.js.map +1 -0
- package/dist/api/pages.js +1180 -0
- package/dist/api/pages.js.map +1 -0
- package/dist/api/routes/api.js +612 -0
- package/dist/api/routes/api.js.map +1 -0
- package/dist/api/routes/browsers.js +471 -0
- package/dist/api/routes/browsers.js.map +1 -0
- package/dist/api/routes/do.js +188 -0
- package/dist/api/routes/do.js.map +1 -0
- package/dist/api/routes/mcp.js +459 -0
- package/dist/api/routes/mcp.js.map +1 -0
- package/dist/api/routes/obs.js +445 -0
- package/dist/api/routes/obs.js.map +1 -0
- package/dist/api/routes/openapi.js +794 -0
- package/dist/api/routes/openapi.js.map +1 -0
- package/dist/api/routes/rpc.js +1103 -0
- package/dist/api/routes/rpc.js.map +1 -0
- package/dist/api/routes/sandboxes.js +389 -0
- package/dist/api/routes/sandboxes.js.map +1 -0
- package/dist/api/test-do.js +38 -0
- package/dist/api/test-do.js.map +1 -0
- package/dist/api/types.js +11 -0
- package/dist/api/types.js.map +1 -0
- package/dist/cli/bin.js +2 -0
- package/dist/cli/main.js +52342 -0
- package/dist/db/actions.js +212 -0
- package/dist/db/actions.js.map +1 -0
- package/dist/db/auth.js +506 -0
- package/dist/db/auth.js.map +1 -0
- package/dist/db/branches.js +65 -0
- package/dist/db/branches.js.map +1 -0
- package/dist/db/clickhouse.js +1074 -0
- package/dist/db/clickhouse.js.map +1 -0
- package/dist/db/dlq.js +39 -0
- package/dist/db/dlq.js.map +1 -0
- package/dist/db/events.js +28 -0
- package/dist/db/events.js.map +1 -0
- package/dist/db/exec.js +64 -0
- package/dist/db/exec.js.map +1 -0
- package/dist/db/files.js +85 -0
- package/dist/db/files.js.map +1 -0
- package/dist/db/flags.js +24 -0
- package/dist/db/flags.js.map +1 -0
- package/dist/db/git.js +116 -0
- package/dist/db/git.js.map +1 -0
- package/dist/db/iceberg/inverted-index.js +862 -0
- package/dist/db/iceberg/inverted-index.js.map +1 -0
- package/dist/db/iceberg/puffin.js +878 -0
- package/dist/db/iceberg/puffin.js.map +1 -0
- package/dist/db/iceberg/search-manifest.js +422 -0
- package/dist/db/iceberg/search-manifest.js.map +1 -0
- package/dist/db/iceberg/types.js +8 -0
- package/dist/db/iceberg/types.js.map +1 -0
- package/dist/db/index.js +121 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/integrations.js +368 -0
- package/dist/db/integrations.js.map +1 -0
- package/dist/db/json-indexes.js +332 -0
- package/dist/db/json-indexes.js.map +1 -0
- package/dist/db/linked-accounts.js +287 -0
- package/dist/db/linked-accounts.js.map +1 -0
- package/dist/db/nouns.js +183 -0
- package/dist/db/nouns.js.map +1 -0
- package/dist/db/objects.js +170 -0
- package/dist/db/objects.js.map +1 -0
- package/dist/db/primitives/dag-scheduler/index.js +869 -0
- package/dist/db/primitives/dag-scheduler/index.js.map +1 -0
- package/dist/db/primitives/exactly-once-context.js +237 -0
- package/dist/db/primitives/exactly-once-context.js.map +1 -0
- package/dist/db/primitives/index.js +62 -0
- package/dist/db/primitives/index.js.map +1 -0
- package/dist/db/primitives/keyed-router.js +145 -0
- package/dist/db/primitives/keyed-router.js.map +1 -0
- package/dist/db/primitives/observability.js +162 -0
- package/dist/db/primitives/observability.js.map +1 -0
- package/dist/db/primitives/schema-evolution.js +643 -0
- package/dist/db/primitives/schema-evolution.js.map +1 -0
- package/dist/db/primitives/stateful-operator/index.js +770 -0
- package/dist/db/primitives/stateful-operator/index.js.map +1 -0
- package/dist/db/primitives/temporal-store.js +306 -0
- package/dist/db/primitives/temporal-store.js.map +1 -0
- package/dist/db/primitives/typed-column-store.js +1229 -0
- package/dist/db/primitives/typed-column-store.js.map +1 -0
- package/dist/db/primitives/utils/duration.js +162 -0
- package/dist/db/primitives/utils/duration.js.map +1 -0
- package/dist/db/primitives/utils/murmur3.js +118 -0
- package/dist/db/primitives/utils/murmur3.js.map +1 -0
- package/dist/db/primitives/watermark-service.js +136 -0
- package/dist/db/primitives/watermark-service.js.map +1 -0
- package/dist/db/primitives/window-manager.js +764 -0
- package/dist/db/primitives/window-manager.js.map +1 -0
- package/dist/db/relationships.js +66 -0
- package/dist/db/relationships.js.map +1 -0
- package/dist/db/schema-minimal.js +61 -0
- package/dist/db/schema-minimal.js.map +1 -0
- package/dist/db/search.js +28 -0
- package/dist/db/search.js.map +1 -0
- package/dist/db/stores.js +1665 -0
- package/dist/db/stores.js.map +1 -0
- package/dist/db/things.js +297 -0
- package/dist/db/things.js.map +1 -0
- package/dist/db/vault.js +171 -0
- package/dist/db/vault.js.map +1 -0
- package/dist/db/verbs.js +102 -0
- package/dist/db/verbs.js.map +1 -0
- package/dist/do/base.js +48 -0
- package/dist/do/base.js.map +1 -0
- package/dist/do/bash.js +35 -0
- package/dist/do/bash.js.map +1 -0
- package/dist/do/fs.js +25 -0
- package/dist/do/fs.js.map +1 -0
- package/dist/do/full.js +61 -0
- package/dist/do/full.js.map +1 -0
- package/dist/do/git.js +28 -0
- package/dist/do/git.js.map +1 -0
- package/dist/do/index.js +52 -0
- package/dist/do/index.js.map +1 -0
- package/dist/do/tiny.js +31 -0
- package/dist/do/tiny.js.map +1 -0
- package/dist/lib/DOAuth.js +261 -0
- package/dist/lib/DOAuth.js.map +1 -0
- package/dist/lib/DODispatcher.js +72 -0
- package/dist/lib/DODispatcher.js.map +1 -0
- package/dist/lib/Modifier.js +189 -0
- package/dist/lib/Modifier.js.map +1 -0
- package/dist/lib/StateStorage.js +403 -0
- package/dist/lib/StateStorage.js.map +1 -0
- package/dist/lib/TypeRegistry.js +122 -0
- package/dist/lib/TypeRegistry.js.map +1 -0
- package/dist/lib/agent/tools/bash.js +336 -0
- package/dist/lib/agent/tools/bash.js.map +1 -0
- package/dist/lib/agent/tools/edit.js +157 -0
- package/dist/lib/agent/tools/edit.js.map +1 -0
- package/dist/lib/agent/tools/glob.js +137 -0
- package/dist/lib/agent/tools/glob.js.map +1 -0
- package/dist/lib/agent/tools/grep.js +315 -0
- package/dist/lib/agent/tools/grep.js.map +1 -0
- package/dist/lib/agent/tools/index.js +71 -0
- package/dist/lib/agent/tools/index.js.map +1 -0
- package/dist/lib/agent/tools/read.js +212 -0
- package/dist/lib/agent/tools/read.js.map +1 -0
- package/dist/lib/agent/tools/types.js +197 -0
- package/dist/lib/agent/tools/types.js.map +1 -0
- package/dist/lib/agent/tools/write.js +159 -0
- package/dist/lib/agent/tools/write.js.map +1 -0
- package/dist/lib/ai/gateway.js +247 -0
- package/dist/lib/ai/gateway.js.map +1 -0
- package/dist/lib/ai/tool-loop-agent.js +591 -0
- package/dist/lib/ai/tool-loop-agent.js.map +1 -0
- package/dist/lib/auto-wiring.js +439 -0
- package/dist/lib/auto-wiring.js.map +1 -0
- package/dist/lib/browse/browserbase.js +163 -0
- package/dist/lib/browse/browserbase.js.map +1 -0
- package/dist/lib/browse/cloudflare.js +144 -0
- package/dist/lib/browse/cloudflare.js.map +1 -0
- package/dist/lib/browse/index.js +62 -0
- package/dist/lib/browse/index.js.map +1 -0
- package/dist/lib/browse/types.js +13 -0
- package/dist/lib/browse/types.js.map +1 -0
- package/dist/lib/cache/index.js +37 -0
- package/dist/lib/cache/index.js.map +1 -0
- package/dist/lib/cache/visibility.js +638 -0
- package/dist/lib/cache/visibility.js.map +1 -0
- package/dist/lib/capabilities.js +268 -0
- package/dist/lib/capabilities.js.map +1 -0
- package/dist/lib/channels/base.js +106 -0
- package/dist/lib/channels/base.js.map +1 -0
- package/dist/lib/channels/discord.js +94 -0
- package/dist/lib/channels/discord.js.map +1 -0
- package/dist/lib/channels/email.js +204 -0
- package/dist/lib/channels/email.js.map +1 -0
- package/dist/lib/channels/index.js +90 -0
- package/dist/lib/channels/index.js.map +1 -0
- package/dist/lib/channels/mdxui-chat.js +95 -0
- package/dist/lib/channels/mdxui-chat.js.map +1 -0
- package/dist/lib/channels/slack-blockkit.js +121 -0
- package/dist/lib/channels/slack-blockkit.js.map +1 -0
- package/dist/lib/channels/types.js +7 -0
- package/dist/lib/channels/types.js.map +1 -0
- package/dist/lib/cloudflare/ai.js +654 -0
- package/dist/lib/cloudflare/ai.js.map +1 -0
- package/dist/lib/cloudflare/index.js +88 -0
- package/dist/lib/cloudflare/index.js.map +1 -0
- package/dist/lib/cloudflare/kv.js +342 -0
- package/dist/lib/cloudflare/kv.js.map +1 -0
- package/dist/lib/cloudflare/queues.js +434 -0
- package/dist/lib/cloudflare/queues.js.map +1 -0
- package/dist/lib/cloudflare/r2.js +604 -0
- package/dist/lib/cloudflare/r2.js.map +1 -0
- package/dist/lib/cloudflare/vectorize.js +494 -0
- package/dist/lib/cloudflare/vectorize.js.map +1 -0
- package/dist/lib/cloudflare/workflows.js +569 -0
- package/dist/lib/cloudflare/workflows.js.map +1 -0
- package/dist/lib/colo/caching.js +196 -0
- package/dist/lib/colo/caching.js.map +1 -0
- package/dist/lib/colo/detection.js +194 -0
- package/dist/lib/colo/detection.js.map +1 -0
- package/dist/lib/colo/external-data.js +219 -0
- package/dist/lib/colo/external-data.js.map +1 -0
- package/dist/lib/colo/globe-data.js +179 -0
- package/dist/lib/colo/globe-data.js.map +1 -0
- package/dist/lib/colo/index.js +16 -0
- package/dist/lib/colo/index.js.map +1 -0
- package/dist/lib/decorators.js +37 -0
- package/dist/lib/decorators.js.map +1 -0
- package/dist/lib/discovery.js +81 -0
- package/dist/lib/discovery.js.map +1 -0
- package/dist/lib/executors/AgenticFunctionExecutor.js +619 -0
- package/dist/lib/executors/AgenticFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/BaseFunctionExecutor.js +328 -0
- package/dist/lib/executors/BaseFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/CascadeExecutor.js +418 -0
- package/dist/lib/executors/CascadeExecutor.js.map +1 -0
- package/dist/lib/executors/CodeFunctionExecutor.js +904 -0
- package/dist/lib/executors/CodeFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/GenerativeFunctionExecutor.js +904 -0
- package/dist/lib/executors/GenerativeFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/HumanFunctionExecutor.js +884 -0
- package/dist/lib/executors/HumanFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/ParallelStepExecutor.js +308 -0
- package/dist/lib/executors/ParallelStepExecutor.js.map +1 -0
- package/dist/lib/executors/types.js +12 -0
- package/dist/lib/executors/types.js.map +1 -0
- package/dist/lib/experiments.js +89 -0
- package/dist/lib/experiments.js.map +1 -0
- package/dist/lib/flags/store.js +262 -0
- package/dist/lib/flags/store.js.map +1 -0
- package/dist/lib/functions/FunctionComposition.js +467 -0
- package/dist/lib/functions/FunctionComposition.js.map +1 -0
- package/dist/lib/functions/FunctionMiddleware.js +457 -0
- package/dist/lib/functions/FunctionMiddleware.js.map +1 -0
- package/dist/lib/functions/FunctionRegistry.js +426 -0
- package/dist/lib/functions/FunctionRegistry.js.map +1 -0
- package/dist/lib/functions/createFunction.js +1048 -0
- package/dist/lib/functions/createFunction.js.map +1 -0
- package/dist/lib/humans/index.js +68 -0
- package/dist/lib/humans/index.js.map +1 -0
- package/dist/lib/humans/templates.js +117 -0
- package/dist/lib/humans/templates.js.map +1 -0
- package/dist/lib/identity.js +98 -0
- package/dist/lib/identity.js.map +1 -0
- package/dist/lib/index.js +9 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/logging/error-logger.js +163 -0
- package/dist/lib/logging/error-logger.js.map +1 -0
- package/dist/lib/logging/index.js +160 -0
- package/dist/lib/logging/index.js.map +1 -0
- package/dist/lib/mixins/bash.js +825 -0
- package/dist/lib/mixins/bash.js.map +1 -0
- package/dist/lib/mixins/fs.js +648 -0
- package/dist/lib/mixins/fs.js.map +1 -0
- package/dist/lib/mixins/git.js +1011 -0
- package/dist/lib/mixins/git.js.map +1 -0
- package/dist/lib/mixins/index.js +29 -0
- package/dist/lib/mixins/index.js.map +1 -0
- package/dist/lib/mixins/npm.js +662 -0
- package/dist/lib/mixins/npm.js.map +1 -0
- package/dist/lib/noun-id.js +278 -0
- package/dist/lib/noun-id.js.map +1 -0
- package/dist/lib/rate-limit/sliding-window.js +148 -0
- package/dist/lib/rate-limit/sliding-window.js.map +1 -0
- package/dist/lib/rate-limit.js +110 -0
- package/dist/lib/rate-limit.js.map +1 -0
- package/dist/lib/rpc/bindings.js +548 -0
- package/dist/lib/rpc/bindings.js.map +1 -0
- package/dist/lib/rpc/index.js +64 -0
- package/dist/lib/rpc/index.js.map +1 -0
- package/dist/lib/safe-stringify.js +223 -0
- package/dist/lib/safe-stringify.js.map +1 -0
- package/dist/lib/sandbox/miniflare-sandbox.js +1007 -0
- package/dist/lib/sandbox/miniflare-sandbox.js.map +1 -0
- package/dist/lib/sqids.js +110 -0
- package/dist/lib/sqids.js.map +1 -0
- package/dist/lib/sql/adapters/index.js +10 -0
- package/dist/lib/sql/adapters/index.js.map +1 -0
- package/dist/lib/sql/adapters/node-sql-parser.js +552 -0
- package/dist/lib/sql/adapters/node-sql-parser.js.map +1 -0
- package/dist/lib/sql/adapters/pgsql-parser.js +1189 -0
- package/dist/lib/sql/adapters/pgsql-parser.js.map +1 -0
- package/dist/lib/sql/index.js +277 -0
- package/dist/lib/sql/index.js.map +1 -0
- package/dist/lib/sql/types.js +56 -0
- package/dist/lib/sql/types.js.map +1 -0
- package/dist/lib/type-classifier.js +126 -0
- package/dist/lib/type-classifier.js.map +1 -0
- package/dist/lib/utils/html.js +47 -0
- package/dist/lib/utils/html.js.map +1 -0
- package/dist/lib/validation.js +48 -0
- package/dist/lib/validation.js.map +1 -0
- package/dist/lib/vault/store.js +411 -0
- package/dist/lib/vault/store.js.map +1 -0
- package/dist/metrics/hunch.js +739 -0
- package/dist/metrics/hunch.js.map +1 -0
- package/dist/objects/API.js +302 -0
- package/dist/objects/API.js.map +1 -0
- package/dist/objects/Agent.js +179 -0
- package/dist/objects/Agent.js.map +1 -0
- package/dist/objects/AgenticFunctionExecutor.js +8 -0
- package/dist/objects/AgenticFunctionExecutor.js.map +1 -0
- package/dist/objects/App.js +83 -0
- package/dist/objects/App.js.map +1 -0
- package/dist/objects/Browser.js +884 -0
- package/dist/objects/Browser.js.map +1 -0
- package/dist/objects/Business.js +107 -0
- package/dist/objects/Business.js.map +1 -0
- package/dist/objects/CLI.js +221 -0
- package/dist/objects/CLI.js.map +1 -0
- package/dist/objects/CodeFunctionExecutor.js +8 -0
- package/dist/objects/CodeFunctionExecutor.js.map +1 -0
- package/dist/objects/Collection.js +161 -0
- package/dist/objects/Collection.js.map +1 -0
- package/dist/objects/DO.js +41 -0
- package/dist/objects/DO.js.map +1 -0
- package/dist/objects/DOBase.js +2309 -0
- package/dist/objects/DOBase.js.map +1 -0
- package/dist/objects/DOFull.js +1676 -0
- package/dist/objects/DOFull.js.map +1 -0
- package/dist/objects/DOTiny.js +207 -0
- package/dist/objects/DOTiny.js.map +1 -0
- package/dist/objects/Directory.js +199 -0
- package/dist/objects/Directory.js.map +1 -0
- package/dist/objects/Entity.js +413 -0
- package/dist/objects/Entity.js.map +1 -0
- package/dist/objects/Function.js +116 -0
- package/dist/objects/Function.js.map +1 -0
- package/dist/objects/Human.js +231 -0
- package/dist/objects/Human.js.map +1 -0
- package/dist/objects/HumanFunctionExecutor.js +8 -0
- package/dist/objects/HumanFunctionExecutor.js.map +1 -0
- package/dist/objects/IcebergMetadataDO.js +938 -0
- package/dist/objects/IcebergMetadataDO.js.map +1 -0
- package/dist/objects/IntegrationsDO.js +1174 -0
- package/dist/objects/IntegrationsDO.js.map +1 -0
- package/dist/objects/ObservabilityBroadcaster.js +149 -0
- package/dist/objects/ObservabilityBroadcaster.js.map +1 -0
- package/dist/objects/Package.js +154 -0
- package/dist/objects/Package.js.map +1 -0
- package/dist/objects/Product.js +193 -0
- package/dist/objects/Product.js.map +1 -0
- package/dist/objects/SDK.js +152 -0
- package/dist/objects/SDK.js.map +1 -0
- package/dist/objects/SaaS.js +235 -0
- package/dist/objects/SaaS.js.map +1 -0
- package/dist/objects/SandboxDO.js +759 -0
- package/dist/objects/SandboxDO.js.map +1 -0
- package/dist/objects/Service.js +337 -0
- package/dist/objects/Service.js.map +1 -0
- package/dist/objects/Site.js +80 -0
- package/dist/objects/Site.js.map +1 -0
- package/dist/objects/Startup.js +479 -0
- package/dist/objects/Startup.js.map +1 -0
- package/dist/objects/ThingsDO.js +170 -0
- package/dist/objects/ThingsDO.js.map +1 -0
- package/dist/objects/VectorShardDO.js +648 -0
- package/dist/objects/VectorShardDO.js.map +1 -0
- package/dist/objects/Worker.js +144 -0
- package/dist/objects/Worker.js.map +1 -0
- package/dist/objects/Workflow.js +196 -0
- package/dist/objects/Workflow.js.map +1 -0
- package/dist/objects/WorkflowFactory.js +313 -0
- package/dist/objects/WorkflowFactory.js.map +1 -0
- package/dist/objects/WorkflowRuntime.js +863 -0
- package/dist/objects/WorkflowRuntime.js.map +1 -0
- package/dist/objects/circuit-breaker-bulkhead.js +178 -0
- package/dist/objects/circuit-breaker-bulkhead.js.map +1 -0
- package/dist/objects/createFunction.js +934 -0
- package/dist/objects/createFunction.js.map +1 -0
- package/dist/objects/index.js +80 -0
- package/dist/objects/index.js.map +1 -0
- package/dist/objects/lifecycle/Branch.js +275 -0
- package/dist/objects/lifecycle/Branch.js.map +1 -0
- package/dist/objects/lifecycle/Clone.js +1499 -0
- package/dist/objects/lifecycle/Clone.js.map +1 -0
- package/dist/objects/lifecycle/Compact.js +237 -0
- package/dist/objects/lifecycle/Compact.js.map +1 -0
- package/dist/objects/lifecycle/Promote.js +476 -0
- package/dist/objects/lifecycle/Promote.js.map +1 -0
- package/dist/objects/lifecycle/Shard.js +560 -0
- package/dist/objects/lifecycle/Shard.js.map +1 -0
- package/dist/objects/lifecycle/index.js +15 -0
- package/dist/objects/lifecycle/index.js.map +1 -0
- package/dist/objects/lifecycle/types.js +33 -0
- package/dist/objects/lifecycle/types.js.map +1 -0
- package/dist/objects/mixins/infrastructure.js +171 -0
- package/dist/objects/mixins/infrastructure.js.map +1 -0
- package/dist/objects/modules/StoresModule.js +153 -0
- package/dist/objects/modules/StoresModule.js.map +1 -0
- package/dist/objects/persistence/checkpoint-manager.js +606 -0
- package/dist/objects/persistence/checkpoint-manager.js.map +1 -0
- package/dist/objects/persistence/index.js +72 -0
- package/dist/objects/persistence/index.js.map +1 -0
- package/dist/objects/persistence/migration-runner.js +562 -0
- package/dist/objects/persistence/migration-runner.js.map +1 -0
- package/dist/objects/persistence/replication-manager.js +501 -0
- package/dist/objects/persistence/replication-manager.js.map +1 -0
- package/dist/objects/persistence/tiered-storage-manager.js +595 -0
- package/dist/objects/persistence/tiered-storage-manager.js.map +1 -0
- package/dist/objects/persistence/types.js +14 -0
- package/dist/objects/persistence/types.js.map +1 -0
- package/dist/objects/persistence/wal-manager.js +653 -0
- package/dist/objects/persistence/wal-manager.js.map +1 -0
- package/dist/objects/presets/index.js +20 -0
- package/dist/objects/presets/index.js.map +1 -0
- package/dist/objects/presets/primitives.js +188 -0
- package/dist/objects/presets/primitives.js.map +1 -0
- package/dist/objects/primitives/alarm-adapter.js +141 -0
- package/dist/objects/primitives/alarm-adapter.js.map +1 -0
- package/dist/objects/primitives/index.js +337 -0
- package/dist/objects/primitives/index.js.map +1 -0
- package/dist/objects/primitives/storage-adapter.js +182 -0
- package/dist/objects/primitives/storage-adapter.js.map +1 -0
- package/dist/objects/primitives/with-primitives.js +102 -0
- package/dist/objects/primitives/with-primitives.js.map +1 -0
- package/dist/objects/services/StoreManager.js +227 -0
- package/dist/objects/services/StoreManager.js.map +1 -0
- package/dist/objects/services/index.js +13 -0
- package/dist/objects/services/index.js.map +1 -0
- package/dist/objects/transport/auth-layer.js +1451 -0
- package/dist/objects/transport/auth-layer.js.map +1 -0
- package/dist/objects/transport/capnweb-target.js +355 -0
- package/dist/objects/transport/capnweb-target.js.map +1 -0
- package/dist/objects/transport/chain.js +441 -0
- package/dist/objects/transport/chain.js.map +1 -0
- package/dist/objects/transport/handler.js +58 -0
- package/dist/objects/transport/handler.js.map +1 -0
- package/dist/objects/transport/index.js +53 -0
- package/dist/objects/transport/index.js.map +1 -0
- package/dist/objects/transport/mcp-server.js +690 -0
- package/dist/objects/transport/mcp-server.js.map +1 -0
- package/dist/objects/transport/rest-autowire.js +1507 -0
- package/dist/objects/transport/rest-autowire.js.map +1 -0
- package/dist/objects/transport/rest-router.js +440 -0
- package/dist/objects/transport/rest-router.js.map +1 -0
- package/dist/objects/transport/rpc-server.js +1536 -0
- package/dist/objects/transport/rpc-server.js.map +1 -0
- package/dist/objects/transport/shared.js +575 -0
- package/dist/objects/transport/shared.js.map +1 -0
- package/dist/objects/transport/sync-engine.js +291 -0
- package/dist/objects/transport/sync-engine.js.map +1 -0
- package/dist/objects/transport/types.js +8 -0
- package/dist/objects/transport/types.js.map +1 -0
- package/dist/primitives/bashx/src/ast/analyze.js +1472 -0
- package/dist/primitives/bashx/src/ast/analyze.js.map +1 -0
- package/dist/primitives/bashx/src/ast/parser.js +1488 -0
- package/dist/primitives/bashx/src/ast/parser.js.map +1 -0
- package/dist/primitives/bashx/src/do/commands/crypto.js +1954 -0
- package/dist/primitives/bashx/src/do/commands/crypto.js.map +1 -0
- package/dist/primitives/bashx/src/do/commands/data-processing.js +1812 -0
- package/dist/primitives/bashx/src/do/commands/data-processing.js.map +1 -0
- package/dist/primitives/bashx/src/do/commands/extended-utils.js +804 -0
- package/dist/primitives/bashx/src/do/commands/extended-utils.js.map +1 -0
- package/dist/primitives/bashx/src/do/commands/math-control.js +1122 -0
- package/dist/primitives/bashx/src/do/commands/math-control.js.map +1 -0
- package/dist/primitives/bashx/src/do/commands/posix-utils.js +1015 -0
- package/dist/primitives/bashx/src/do/commands/posix-utils.js.map +1 -0
- package/dist/primitives/bashx/src/do/commands/system-utils.js +687 -0
- package/dist/primitives/bashx/src/do/commands/system-utils.js.map +1 -0
- package/dist/primitives/bashx/src/do/commands/test-command.js +523 -0
- package/dist/primitives/bashx/src/do/commands/test-command.js.map +1 -0
- package/dist/primitives/bashx/src/do/commands/text-processing.js +1550 -0
- package/dist/primitives/bashx/src/do/commands/text-processing.js.map +1 -0
- package/dist/primitives/bashx/src/do/container-executor.js +429 -0
- package/dist/primitives/bashx/src/do/container-executor.js.map +1 -0
- package/dist/primitives/bashx/src/do/index.js +668 -0
- package/dist/primitives/bashx/src/do/index.js.map +1 -0
- package/dist/primitives/bashx/src/do/tiered-executor.js +2647 -0
- package/dist/primitives/bashx/src/do/tiered-executor.js.map +1 -0
- package/dist/primitives/bashx/src/do/worker.js +352 -0
- package/dist/primitives/bashx/src/do/worker.js.map +1 -0
- package/dist/primitives/bashx/src/types.js +10 -0
- package/dist/primitives/bashx/src/types.js.map +1 -0
- package/dist/primitives/fsx/core/backend.js +480 -0
- package/dist/primitives/fsx/core/backend.js.map +1 -0
- package/dist/primitives/fsx/core/constants.js +140 -0
- package/dist/primitives/fsx/core/constants.js.map +1 -0
- package/dist/primitives/fsx/core/fsx.js +1184 -0
- package/dist/primitives/fsx/core/fsx.js.map +1 -0
- package/dist/primitives/fsx/core/glob/glob.js +438 -0
- package/dist/primitives/fsx/core/glob/glob.js.map +1 -0
- package/dist/primitives/fsx/core/glob/index.js +8 -0
- package/dist/primitives/fsx/core/glob/index.js.map +1 -0
- package/dist/primitives/fsx/core/glob/match.js +392 -0
- package/dist/primitives/fsx/core/glob/match.js.map +1 -0
- package/dist/primitives/fsx/core/types.js +307 -0
- package/dist/primitives/fsx/core/types.js.map +1 -0
- package/dist/sandbox/index.js +258 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sdk/capnweb-compat.js +42 -0
- package/dist/sdk/capnweb-compat.js.map +1 -0
- package/dist/sdk/client.js +20 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/index.js +17 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/snippets/artifacts-config.js +241 -0
- package/dist/snippets/artifacts-config.js.map +1 -0
- package/dist/snippets/artifacts-ingest.js +832 -0
- package/dist/snippets/artifacts-ingest.js.map +1 -0
- package/dist/snippets/artifacts-serve.js +1035 -0
- package/dist/snippets/artifacts-serve.js.map +1 -0
- package/dist/snippets/artifacts-types.js +161 -0
- package/dist/snippets/artifacts-types.js.map +1 -0
- package/dist/snippets/cache-probe.js +376 -0
- package/dist/snippets/cache-probe.js.map +1 -0
- package/dist/snippets/cache.js +10 -0
- package/dist/snippets/cache.js.map +1 -0
- package/dist/snippets/events.js +469 -0
- package/dist/snippets/events.js.map +1 -0
- package/dist/snippets/index.js +7 -0
- package/dist/snippets/index.js.map +1 -0
- package/dist/snippets/proxy.js +495 -0
- package/dist/snippets/proxy.js.map +1 -0
- package/dist/snippets/search.js +1759 -0
- package/dist/snippets/search.js.map +1 -0
- package/dist/streams/index.js +30 -0
- package/dist/streams/index.js.map +1 -0
- package/dist/streams/observability.js +68 -0
- package/dist/streams/observability.js.map +1 -0
- package/dist/types/AI.js +92 -0
- package/dist/types/AI.js.map +1 -0
- package/dist/types/AIFunction.js +171 -0
- package/dist/types/AIFunction.js.map +1 -0
- package/dist/types/BrowseVerb.js +89 -0
- package/dist/types/BrowseVerb.js.map +1 -0
- package/dist/types/Browser.js +31 -0
- package/dist/types/Browser.js.map +1 -0
- package/dist/types/Chaos.js +15 -0
- package/dist/types/Chaos.js.map +1 -0
- package/dist/types/CloudflareBindings.js +109 -0
- package/dist/types/CloudflareBindings.js.map +1 -0
- package/dist/types/Collection.js +50 -0
- package/dist/types/Collection.js.map +1 -0
- package/dist/types/DO.js +2 -0
- package/dist/types/DO.js.map +1 -0
- package/dist/types/DOLocation.js +63 -0
- package/dist/types/DOLocation.js.map +1 -0
- package/dist/types/EventHandler.js +57 -0
- package/dist/types/EventHandler.js.map +1 -0
- package/dist/types/Experiment.js +33 -0
- package/dist/types/Experiment.js.map +1 -0
- package/dist/types/Flag.js +57 -0
- package/dist/types/Flag.js.map +1 -0
- package/dist/types/Lifecycle.js +13 -0
- package/dist/types/Lifecycle.js.map +1 -0
- package/dist/types/Location.js +169 -0
- package/dist/types/Location.js.map +1 -0
- package/dist/types/Noun.js +66 -0
- package/dist/types/Noun.js.map +1 -0
- package/dist/types/SessionEvent.js +194 -0
- package/dist/types/SessionEvent.js.map +1 -0
- package/dist/types/Thing.js +55 -0
- package/dist/types/Thing.js.map +1 -0
- package/dist/types/ThingDO.js +153 -0
- package/dist/types/ThingDO.js.map +1 -0
- package/dist/types/Things.js +2 -0
- package/dist/types/Things.js.map +1 -0
- package/dist/types/Verb.js +119 -0
- package/dist/types/Verb.js.map +1 -0
- package/dist/types/WorkflowContext.js +70 -0
- package/dist/types/WorkflowContext.js.map +1 -0
- package/dist/types/analytics-api.js +13 -0
- package/dist/types/analytics-api.js.map +1 -0
- package/dist/types/capabilities.js +135 -0
- package/dist/types/capabilities.js.map +1 -0
- package/dist/types/drizzle.js +12 -0
- package/dist/types/drizzle.js.map +1 -0
- package/dist/types/event.js +201 -0
- package/dist/types/event.js.map +1 -0
- package/dist/types/fn.js +12 -0
- package/dist/types/fn.js.map +1 -0
- package/dist/types/iceberg.js +48 -0
- package/dist/types/iceberg.js.map +1 -0
- package/dist/types/ids.js +170 -0
- package/dist/types/ids.js.map +1 -0
- package/dist/types/index.js +41 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/introspect.js +54 -0
- package/dist/types/introspect.js.map +1 -0
- package/dist/types/observability.js +124 -0
- package/dist/types/observability.js.map +1 -0
- package/dist/types/sync-protocol.js +175 -0
- package/dist/types/sync-protocol.js.map +1 -0
- package/dist/types/vector.js +13 -0
- package/dist/types/vector.js.map +1 -0
- package/dist/workflows/ScheduleManager.js +473 -0
- package/dist/workflows/ScheduleManager.js.map +1 -0
- package/dist/workflows/StepDOBridge.js +149 -0
- package/dist/workflows/StepDOBridge.js.map +1 -0
- package/dist/workflows/StepResultStorage.js +232 -0
- package/dist/workflows/StepResultStorage.js.map +1 -0
- package/dist/workflows/WaitForEventManager.js +461 -0
- package/dist/workflows/WaitForEventManager.js.map +1 -0
- package/dist/workflows/analyzer.js +332 -0
- package/dist/workflows/analyzer.js.map +1 -0
- package/dist/workflows/compat/activity-router.js +484 -0
- package/dist/workflows/compat/activity-router.js.map +1 -0
- package/dist/workflows/compat/backends/cloudflare-workflows.js +431 -0
- package/dist/workflows/compat/backends/cloudflare-workflows.js.map +1 -0
- package/dist/workflows/compat/backends/index.js +14 -0
- package/dist/workflows/compat/backends/index.js.map +1 -0
- package/dist/workflows/compat/errors/index.js +375 -0
- package/dist/workflows/compat/errors/index.js.map +1 -0
- package/dist/workflows/compat/index.js +79 -0
- package/dist/workflows/compat/index.js.map +1 -0
- package/dist/workflows/compat/inngest/index.js +989 -0
- package/dist/workflows/compat/inngest/index.js.map +1 -0
- package/dist/workflows/compat/qstash/index.js +1263 -0
- package/dist/workflows/compat/qstash/index.js.map +1 -0
- package/dist/workflows/compat/temporal/activities.js +739 -0
- package/dist/workflows/compat/temporal/activities.js.map +1 -0
- package/dist/workflows/compat/temporal/child-workflows.js +154 -0
- package/dist/workflows/compat/temporal/child-workflows.js.map +1 -0
- package/dist/workflows/compat/temporal/client.js +381 -0
- package/dist/workflows/compat/temporal/client.js.map +1 -0
- package/dist/workflows/compat/temporal/context.js +309 -0
- package/dist/workflows/compat/temporal/context.js.map +1 -0
- package/dist/workflows/compat/temporal/determinism.js +216 -0
- package/dist/workflows/compat/temporal/determinism.js.map +1 -0
- package/dist/workflows/compat/temporal/errors.js +128 -0
- package/dist/workflows/compat/temporal/errors.js.map +1 -0
- package/dist/workflows/compat/temporal/index.js +2464 -0
- package/dist/workflows/compat/temporal/index.js.map +1 -0
- package/dist/workflows/compat/temporal/saga.js +504 -0
- package/dist/workflows/compat/temporal/saga.js.map +1 -0
- package/dist/workflows/compat/temporal/signals.js +364 -0
- package/dist/workflows/compat/temporal/signals.js.map +1 -0
- package/dist/workflows/compat/temporal/storage.js +271 -0
- package/dist/workflows/compat/temporal/storage.js.map +1 -0
- package/dist/workflows/compat/temporal/timers.js +347 -0
- package/dist/workflows/compat/temporal/timers.js.map +1 -0
- package/dist/workflows/compat/temporal/types.js +7 -0
- package/dist/workflows/compat/temporal/types.js.map +1 -0
- package/dist/workflows/compat/temporal/unified-primitives.js +339 -0
- package/dist/workflows/compat/temporal/unified-primitives.js.map +1 -0
- package/dist/workflows/compat/trigger/index.js +468 -0
- package/dist/workflows/compat/trigger/index.js.map +1 -0
- package/dist/workflows/compat/utils/index.js +69 -0
- package/dist/workflows/compat/utils/index.js.map +1 -0
- package/dist/workflows/context/correlation-capability.js +266 -0
- package/dist/workflows/context/correlation-capability.js.map +1 -0
- package/dist/workflows/context/correlation.js +484 -0
- package/dist/workflows/context/correlation.js.map +1 -0
- package/dist/workflows/context/experiment.js +289 -0
- package/dist/workflows/context/experiment.js.map +1 -0
- package/dist/workflows/context/flag.js +244 -0
- package/dist/workflows/context/flag.js.map +1 -0
- package/dist/workflows/context/foundation.js +648 -0
- package/dist/workflows/context/foundation.js.map +1 -0
- package/dist/workflows/context/human-base.js +106 -0
- package/dist/workflows/context/human-base.js.map +1 -0
- package/dist/workflows/context/human.js +368 -0
- package/dist/workflows/context/human.js.map +1 -0
- package/dist/workflows/context/measure.js +354 -0
- package/dist/workflows/context/measure.js.map +1 -0
- package/dist/workflows/context/rate-limit.js +358 -0
- package/dist/workflows/context/rate-limit.js.map +1 -0
- package/dist/workflows/context/user.js +117 -0
- package/dist/workflows/context/user.js.map +1 -0
- package/dist/workflows/context/vault.js +360 -0
- package/dist/workflows/context/vault.js.map +1 -0
- package/dist/workflows/data/entity-events/entity-events.js +489 -0
- package/dist/workflows/data/entity-events/entity-events.js.map +1 -0
- package/dist/workflows/data/experiment/index.js +599 -0
- package/dist/workflows/data/experiment/index.js.map +1 -0
- package/dist/workflows/data/goal/context.js +558 -0
- package/dist/workflows/data/goal/context.js.map +1 -0
- package/dist/workflows/data/goal/index.js +32 -0
- package/dist/workflows/data/goal/index.js.map +1 -0
- package/dist/workflows/data/measure/index.js +840 -0
- package/dist/workflows/data/measure/index.js.map +1 -0
- package/dist/workflows/data/stream/index.js +1215 -0
- package/dist/workflows/data/stream/index.js.map +1 -0
- package/dist/workflows/data/track/context.js +883 -0
- package/dist/workflows/data/track/context.js.map +1 -0
- package/dist/workflows/data/track/index.js +15 -0
- package/dist/workflows/data/track/index.js.map +1 -0
- package/dist/workflows/data/view/context.js +864 -0
- package/dist/workflows/data/view/context.js.map +1 -0
- package/dist/workflows/domain.js +93 -0
- package/dist/workflows/domain.js.map +1 -0
- package/dist/workflows/flag.js +176 -0
- package/dist/workflows/flag.js.map +1 -0
- package/dist/workflows/flags.js +217 -0
- package/dist/workflows/flags.js.map +1 -0
- package/dist/workflows/hash.js +209 -0
- package/dist/workflows/hash.js.map +1 -0
- package/dist/workflows/index.js +50 -0
- package/dist/workflows/index.js.map +1 -0
- package/dist/workflows/on.js +378 -0
- package/dist/workflows/on.js.map +1 -0
- package/dist/workflows/pipeline-promise.js +481 -0
- package/dist/workflows/pipeline-promise.js.map +1 -0
- package/dist/workflows/pipeline-types.js +20 -0
- package/dist/workflows/pipeline-types.js.map +1 -0
- package/dist/workflows/proxy.js +76 -0
- package/dist/workflows/proxy.js.map +1 -0
- package/dist/workflows/runtime.js +310 -0
- package/dist/workflows/runtime.js.map +1 -0
- package/dist/workflows/schedule-builder.js +327 -0
- package/dist/workflows/schedule-builder.js.map +1 -0
- package/dist/workflows/visibility/index.js +148 -0
- package/dist/workflows/visibility/index.js.map +1 -0
- package/dist/workflows/visibility/query-parser.js +150 -0
- package/dist/workflows/visibility/query-parser.js.map +1 -0
- package/dist/workflows/visibility/store.js +223 -0
- package/dist/workflows/visibility/store.js.map +1 -0
- package/dist/workflows/visibility/types.js +30 -0
- package/dist/workflows/visibility/types.js.map +1 -0
- package/dist/workflows/workflow.js +53 -0
- package/dist/workflows/workflow.js.map +1 -0
- package/package.json +279 -46
|
@@ -0,0 +1,1229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypedColumnStore - Columnar storage with compression codecs
|
|
3
|
+
*
|
|
4
|
+
* A column-oriented data store optimized for analytical workloads with
|
|
5
|
+
* specialized compression codecs and statistical operations.
|
|
6
|
+
*
|
|
7
|
+
* Key features:
|
|
8
|
+
* - Gorilla XOR compression for floating-point time series
|
|
9
|
+
* - Delta-of-delta encoding for timestamps
|
|
10
|
+
* - Run-length encoding (RLE) for low-cardinality data
|
|
11
|
+
* - ZSTD-like general-purpose compression (using deflate)
|
|
12
|
+
* - Bloom filters for membership testing
|
|
13
|
+
* - HyperLogLog for distinct count estimation
|
|
14
|
+
*
|
|
15
|
+
* @module db/primitives/typed-column-store
|
|
16
|
+
*/
|
|
17
|
+
import { murmurHash3_32 } from './utils/murmur3';
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Bloom Filter Implementation
|
|
20
|
+
// ============================================================================
|
|
21
|
+
class BloomFilterImpl {
|
|
22
|
+
bits;
|
|
23
|
+
numHashFunctions;
|
|
24
|
+
numBits;
|
|
25
|
+
numElements;
|
|
26
|
+
constructor(expectedElements, falsePositiveRate = 0.005) {
|
|
27
|
+
// Calculate optimal number of bits: m = -n * ln(p) / (ln(2)^2)
|
|
28
|
+
// Use slightly lower FPR for safety margin
|
|
29
|
+
const targetFPR = falsePositiveRate * 0.5;
|
|
30
|
+
const ln2Squared = Math.LN2 * Math.LN2;
|
|
31
|
+
this.numBits = Math.max(64, Math.ceil((-expectedElements * Math.log(targetFPR)) / ln2Squared));
|
|
32
|
+
// Round up to nearest byte
|
|
33
|
+
const numBytes = Math.ceil(this.numBits / 8);
|
|
34
|
+
this.bits = new Uint8Array(numBytes);
|
|
35
|
+
// k = (m/n) * ln(2)
|
|
36
|
+
this.numHashFunctions = Math.max(1, Math.min(20, Math.round((this.numBits / expectedElements) * Math.LN2)));
|
|
37
|
+
this.numElements = expectedElements;
|
|
38
|
+
}
|
|
39
|
+
add(value) {
|
|
40
|
+
const key = this.valueToBytes(value);
|
|
41
|
+
const h1 = murmurHash3_32(key, 0);
|
|
42
|
+
const h2 = murmurHash3_32(key, h1);
|
|
43
|
+
for (let i = 0; i < this.numHashFunctions; i++) {
|
|
44
|
+
const combinedHash = (h1 + i * h2) >>> 0;
|
|
45
|
+
const bitIndex = combinedHash % this.numBits;
|
|
46
|
+
const byteIndex = Math.floor(bitIndex / 8);
|
|
47
|
+
const bitOffset = bitIndex % 8;
|
|
48
|
+
this.bits[byteIndex] |= 1 << bitOffset;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
mightContain(value) {
|
|
52
|
+
const key = this.valueToBytes(value);
|
|
53
|
+
const h1 = murmurHash3_32(key, 0);
|
|
54
|
+
const h2 = murmurHash3_32(key, h1);
|
|
55
|
+
for (let i = 0; i < this.numHashFunctions; i++) {
|
|
56
|
+
const combinedHash = (h1 + i * h2) >>> 0;
|
|
57
|
+
const bitIndex = combinedHash % this.numBits;
|
|
58
|
+
const byteIndex = Math.floor(bitIndex / 8);
|
|
59
|
+
const bitOffset = bitIndex % 8;
|
|
60
|
+
if ((this.bits[byteIndex] & (1 << bitOffset)) === 0) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
falsePositiveRate() {
|
|
67
|
+
// FPR = (1 - e^(-kn/m))^k
|
|
68
|
+
return Math.pow(1 - Math.exp((-this.numHashFunctions * this.numElements) / this.numBits), this.numHashFunctions);
|
|
69
|
+
}
|
|
70
|
+
valueToBytes(value) {
|
|
71
|
+
if (typeof value === 'string') {
|
|
72
|
+
return new TextEncoder().encode(value);
|
|
73
|
+
}
|
|
74
|
+
// For numbers, convert to 8-byte representation
|
|
75
|
+
const buffer = new ArrayBuffer(8);
|
|
76
|
+
const view = new DataView(buffer);
|
|
77
|
+
if (Number.isInteger(value)) {
|
|
78
|
+
// Use BigInt64 for integers
|
|
79
|
+
view.setBigInt64(0, BigInt(Math.round(value)), true);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Use Float64 for floats
|
|
83
|
+
view.setFloat64(0, value, true);
|
|
84
|
+
}
|
|
85
|
+
return new Uint8Array(buffer);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ============================================================================
|
|
89
|
+
// HyperLogLog Implementation (for distinct count estimation)
|
|
90
|
+
// ============================================================================
|
|
91
|
+
class HyperLogLog {
|
|
92
|
+
registers;
|
|
93
|
+
numRegisters;
|
|
94
|
+
alpha;
|
|
95
|
+
constructor(precision = 14) {
|
|
96
|
+
// Use precision bits for register addressing
|
|
97
|
+
this.numRegisters = 1 << precision;
|
|
98
|
+
this.registers = new Uint8Array(this.numRegisters);
|
|
99
|
+
// Alpha constant for bias correction
|
|
100
|
+
if (this.numRegisters === 16) {
|
|
101
|
+
this.alpha = 0.673;
|
|
102
|
+
}
|
|
103
|
+
else if (this.numRegisters === 32) {
|
|
104
|
+
this.alpha = 0.697;
|
|
105
|
+
}
|
|
106
|
+
else if (this.numRegisters === 64) {
|
|
107
|
+
this.alpha = 0.709;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.alpha = 0.7213 / (1 + 1.079 / this.numRegisters);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
add(value) {
|
|
114
|
+
const hash = this.hash(value);
|
|
115
|
+
// Use first log2(numRegisters) bits for register index
|
|
116
|
+
const registerBits = Math.log2(this.numRegisters);
|
|
117
|
+
const registerIndex = hash >>> (32 - registerBits);
|
|
118
|
+
// Count leading zeros in remaining bits + 1
|
|
119
|
+
const remainingBits = (hash << registerBits) >>> 0;
|
|
120
|
+
const leadingZeros = this.countLeadingZeros(remainingBits, 32 - registerBits) + 1;
|
|
121
|
+
// Update register with max
|
|
122
|
+
if (leadingZeros > this.registers[registerIndex]) {
|
|
123
|
+
this.registers[registerIndex] = leadingZeros;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
estimate() {
|
|
127
|
+
// Calculate raw estimate using harmonic mean
|
|
128
|
+
let sum = 0;
|
|
129
|
+
for (let i = 0; i < this.numRegisters; i++) {
|
|
130
|
+
sum += Math.pow(2, -this.registers[i]);
|
|
131
|
+
}
|
|
132
|
+
const rawEstimate = (this.alpha * this.numRegisters * this.numRegisters) / sum;
|
|
133
|
+
// Apply corrections
|
|
134
|
+
if (rawEstimate <= 2.5 * this.numRegisters) {
|
|
135
|
+
// Small range correction
|
|
136
|
+
let zeroCount = 0;
|
|
137
|
+
for (let i = 0; i < this.numRegisters; i++) {
|
|
138
|
+
if (this.registers[i] === 0)
|
|
139
|
+
zeroCount++;
|
|
140
|
+
}
|
|
141
|
+
if (zeroCount > 0) {
|
|
142
|
+
return this.numRegisters * Math.log(this.numRegisters / zeroCount);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// For larger estimates, use raw estimate
|
|
146
|
+
return rawEstimate;
|
|
147
|
+
}
|
|
148
|
+
hash(value) {
|
|
149
|
+
let bytes;
|
|
150
|
+
if (typeof value === 'string') {
|
|
151
|
+
bytes = new TextEncoder().encode(value);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const buffer = new ArrayBuffer(8);
|
|
155
|
+
const view = new DataView(buffer);
|
|
156
|
+
view.setFloat64(0, value, true);
|
|
157
|
+
bytes = new Uint8Array(buffer);
|
|
158
|
+
}
|
|
159
|
+
return murmurHash3_32(bytes, 0);
|
|
160
|
+
}
|
|
161
|
+
countLeadingZeros(value, maxBits) {
|
|
162
|
+
if (value === 0)
|
|
163
|
+
return maxBits;
|
|
164
|
+
let count = 0;
|
|
165
|
+
let mask = 1 << (maxBits - 1);
|
|
166
|
+
while ((value & mask) === 0 && count < maxBits) {
|
|
167
|
+
count++;
|
|
168
|
+
mask >>>= 1;
|
|
169
|
+
}
|
|
170
|
+
return count;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// Bit Stream Helper
|
|
175
|
+
// ============================================================================
|
|
176
|
+
class BitWriter {
|
|
177
|
+
buffer = [];
|
|
178
|
+
currentByte = 0;
|
|
179
|
+
bitPos = 0;
|
|
180
|
+
writeBit(bit) {
|
|
181
|
+
if (bit) {
|
|
182
|
+
this.currentByte |= 1 << (7 - this.bitPos);
|
|
183
|
+
}
|
|
184
|
+
this.bitPos++;
|
|
185
|
+
if (this.bitPos === 8) {
|
|
186
|
+
this.buffer.push(this.currentByte);
|
|
187
|
+
this.currentByte = 0;
|
|
188
|
+
this.bitPos = 0;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
writeBits(value, numBits) {
|
|
192
|
+
for (let i = numBits - 1; i >= 0; i--) {
|
|
193
|
+
this.writeBit(((value >> BigInt(i)) & 1n) === 1n);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
writeUint(value, numBits) {
|
|
197
|
+
for (let i = numBits - 1; i >= 0; i--) {
|
|
198
|
+
this.writeBit(((value >> i) & 1) === 1);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
finish() {
|
|
202
|
+
if (this.bitPos > 0) {
|
|
203
|
+
this.buffer.push(this.currentByte);
|
|
204
|
+
}
|
|
205
|
+
return new Uint8Array(this.buffer);
|
|
206
|
+
}
|
|
207
|
+
get byteLength() {
|
|
208
|
+
return this.buffer.length + (this.bitPos > 0 ? 1 : 0);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
class BitReader {
|
|
212
|
+
data;
|
|
213
|
+
bytePos = 0;
|
|
214
|
+
bitPos = 0;
|
|
215
|
+
constructor(data) {
|
|
216
|
+
this.data = data;
|
|
217
|
+
}
|
|
218
|
+
readBit() {
|
|
219
|
+
if (this.bytePos >= this.data.length)
|
|
220
|
+
return false;
|
|
221
|
+
const bit = (this.data[this.bytePos] >> (7 - this.bitPos)) & 1;
|
|
222
|
+
this.bitPos++;
|
|
223
|
+
if (this.bitPos === 8) {
|
|
224
|
+
this.bytePos++;
|
|
225
|
+
this.bitPos = 0;
|
|
226
|
+
}
|
|
227
|
+
return bit === 1;
|
|
228
|
+
}
|
|
229
|
+
readBits(numBits) {
|
|
230
|
+
let result = 0n;
|
|
231
|
+
for (let i = 0; i < numBits; i++) {
|
|
232
|
+
result = (result << 1n) | (this.readBit() ? 1n : 0n);
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
readUint(numBits) {
|
|
237
|
+
let result = 0;
|
|
238
|
+
for (let i = 0; i < numBits; i++) {
|
|
239
|
+
result = (result << 1) | (this.readBit() ? 1 : 0);
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
hasMore() {
|
|
244
|
+
return this.bytePos < this.data.length;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// ============================================================================
|
|
248
|
+
// Gorilla XOR Compression
|
|
249
|
+
// ============================================================================
|
|
250
|
+
/**
|
|
251
|
+
* Gorilla XOR compression for floating-point time series
|
|
252
|
+
*
|
|
253
|
+
* Stores XOR of current value with previous value, then variable-length
|
|
254
|
+
* encodes the meaningful bits using the Facebook Gorilla paper algorithm.
|
|
255
|
+
*
|
|
256
|
+
* For small arrays, uses a simpler encoding to avoid header overhead dominating.
|
|
257
|
+
*/
|
|
258
|
+
class GorillaCodec {
|
|
259
|
+
encode(values) {
|
|
260
|
+
if (values.length === 0) {
|
|
261
|
+
return new Uint8Array([0, 0, 0, 0]);
|
|
262
|
+
}
|
|
263
|
+
const writer = new BitWriter();
|
|
264
|
+
// Write all values as bits for bit-level packing
|
|
265
|
+
// First value: full 64 bits
|
|
266
|
+
const firstBits = this.float64ToBits(values[0]);
|
|
267
|
+
writer.writeBits(firstBits, 64);
|
|
268
|
+
let prevBits = firstBits;
|
|
269
|
+
let prevLeadingZeros = 255; // Initialize to invalid value
|
|
270
|
+
let prevTrailingZeros = 0;
|
|
271
|
+
// Encode subsequent values using XOR with Gorilla algorithm
|
|
272
|
+
for (let i = 1; i < values.length; i++) {
|
|
273
|
+
const currentBits = this.float64ToBits(values[i]);
|
|
274
|
+
const xor = prevBits ^ currentBits;
|
|
275
|
+
if (xor === 0n) {
|
|
276
|
+
// Same as previous - single 0 bit
|
|
277
|
+
writer.writeBit(false);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
// Different - write 1 bit
|
|
281
|
+
writer.writeBit(true);
|
|
282
|
+
const leadingZeros = this.countLeadingZeros64(xor);
|
|
283
|
+
const trailingZeros = this.countTrailingZeros64(xor);
|
|
284
|
+
const meaningfulBits = 64 - leadingZeros - trailingZeros;
|
|
285
|
+
// Check if we can reuse previous block structure
|
|
286
|
+
// (only if previous block was valid and current XOR fits within it)
|
|
287
|
+
if (prevLeadingZeros !== 255 &&
|
|
288
|
+
leadingZeros >= prevLeadingZeros &&
|
|
289
|
+
trailingZeros >= prevTrailingZeros) {
|
|
290
|
+
// Control bit 0: reuse previous block
|
|
291
|
+
writer.writeBit(false);
|
|
292
|
+
// Write meaningful bits using previous block structure
|
|
293
|
+
const prevMeaningfulBits = 64 - prevLeadingZeros - prevTrailingZeros;
|
|
294
|
+
const shifted = xor >> BigInt(prevTrailingZeros);
|
|
295
|
+
writer.writeBits(shifted, prevMeaningfulBits);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
// Control bit 1: new block
|
|
299
|
+
writer.writeBit(true);
|
|
300
|
+
// Write leading zeros (6 bits to support up to 63)
|
|
301
|
+
writer.writeUint(leadingZeros, 6);
|
|
302
|
+
// Write meaningful bits length (6 bits, 0 means 64)
|
|
303
|
+
const mbitsEncoded = meaningfulBits === 64 ? 0 : meaningfulBits;
|
|
304
|
+
writer.writeUint(mbitsEncoded, 6);
|
|
305
|
+
// Write meaningful bits
|
|
306
|
+
const shifted = xor >> BigInt(trailingZeros);
|
|
307
|
+
writer.writeBits(shifted, meaningfulBits);
|
|
308
|
+
prevLeadingZeros = leadingZeros;
|
|
309
|
+
prevTrailingZeros = trailingZeros;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
prevBits = currentBits;
|
|
313
|
+
}
|
|
314
|
+
const bitBytes = writer.finish();
|
|
315
|
+
// Output: [length 4B][bit stream...]
|
|
316
|
+
// More compact - no separate first value storage
|
|
317
|
+
const output = new Uint8Array(4 + bitBytes.length);
|
|
318
|
+
const view = new DataView(output.buffer);
|
|
319
|
+
view.setUint32(0, values.length, true);
|
|
320
|
+
output.set(bitBytes, 4);
|
|
321
|
+
return output;
|
|
322
|
+
}
|
|
323
|
+
decode(data) {
|
|
324
|
+
// Validate minimum buffer size for header
|
|
325
|
+
if (data.length < 4) {
|
|
326
|
+
if (data.length === 0)
|
|
327
|
+
return [];
|
|
328
|
+
throw new Error('Gorilla decode error: Buffer too small - expected at least 4 bytes for header');
|
|
329
|
+
}
|
|
330
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
331
|
+
const length = view.getUint32(0, true);
|
|
332
|
+
if (length === 0)
|
|
333
|
+
return [];
|
|
334
|
+
// Validate buffer has enough data for at least the first value (8 bytes = 64 bits)
|
|
335
|
+
// Header (4 bytes) + at least 8 bytes for first float
|
|
336
|
+
if (data.length < 12) {
|
|
337
|
+
throw new Error('Gorilla decode error: Buffer truncated - insufficient data for first value');
|
|
338
|
+
}
|
|
339
|
+
// Sanity check: prevent unreasonable length values that could cause memory issues
|
|
340
|
+
if (length > 100_000_000) {
|
|
341
|
+
throw new Error(`Gorilla decode error: Invalid length ${length} - exceeds maximum allowed (100M values)`);
|
|
342
|
+
}
|
|
343
|
+
const reader = new BitReader(data.slice(4));
|
|
344
|
+
// Read first value (full 64 bits)
|
|
345
|
+
const firstBits = reader.readBits(64);
|
|
346
|
+
const values = [this.bitsToFloat64(firstBits)];
|
|
347
|
+
if (length === 1)
|
|
348
|
+
return values;
|
|
349
|
+
let prevBits = firstBits;
|
|
350
|
+
let prevLeadingZeros = 255;
|
|
351
|
+
let prevMeaningfulBits = 0;
|
|
352
|
+
let prevTrailingZeros = 0;
|
|
353
|
+
for (let i = 1; i < length; i++) {
|
|
354
|
+
const controlBit = reader.readBit();
|
|
355
|
+
if (!controlBit) {
|
|
356
|
+
// Same as previous
|
|
357
|
+
values.push(this.bitsToFloat64(prevBits));
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
// Different value
|
|
361
|
+
const blockControl = reader.readBit();
|
|
362
|
+
let leadingZeros;
|
|
363
|
+
let meaningfulBits;
|
|
364
|
+
let trailingZeros;
|
|
365
|
+
if (!blockControl && prevLeadingZeros !== 255) {
|
|
366
|
+
// Reuse previous block structure
|
|
367
|
+
leadingZeros = prevLeadingZeros;
|
|
368
|
+
meaningfulBits = prevMeaningfulBits;
|
|
369
|
+
trailingZeros = prevTrailingZeros;
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
// New block structure (or first different value)
|
|
373
|
+
leadingZeros = reader.readUint(6); // 6 bits to support up to 63
|
|
374
|
+
meaningfulBits = reader.readUint(6);
|
|
375
|
+
// Handle edge case where meaningfulBits is 0 (meaning 64)
|
|
376
|
+
if (meaningfulBits === 0)
|
|
377
|
+
meaningfulBits = 64;
|
|
378
|
+
trailingZeros = 64 - leadingZeros - meaningfulBits;
|
|
379
|
+
// Validate block structure
|
|
380
|
+
if (trailingZeros < 0) {
|
|
381
|
+
throw new Error(`Gorilla decode error: Invalid block structure at value ${i} - leadingZeros(${leadingZeros}) + meaningfulBits(${meaningfulBits}) > 64`);
|
|
382
|
+
}
|
|
383
|
+
prevLeadingZeros = leadingZeros;
|
|
384
|
+
prevMeaningfulBits = meaningfulBits;
|
|
385
|
+
prevTrailingZeros = trailingZeros;
|
|
386
|
+
}
|
|
387
|
+
// Read meaningful bits
|
|
388
|
+
const xorValue = reader.readBits(meaningfulBits);
|
|
389
|
+
// Shift to correct position
|
|
390
|
+
const shifted = xorValue << BigInt(trailingZeros);
|
|
391
|
+
// XOR with previous to get current value
|
|
392
|
+
const currentBits = prevBits ^ shifted;
|
|
393
|
+
values.push(this.bitsToFloat64(currentBits));
|
|
394
|
+
prevBits = currentBits;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return values;
|
|
398
|
+
}
|
|
399
|
+
float64ToBits(value) {
|
|
400
|
+
const buffer = new ArrayBuffer(8);
|
|
401
|
+
const view = new DataView(buffer);
|
|
402
|
+
view.setFloat64(0, value, false);
|
|
403
|
+
return view.getBigUint64(0, false);
|
|
404
|
+
}
|
|
405
|
+
bitsToFloat64(bits) {
|
|
406
|
+
const buffer = new ArrayBuffer(8);
|
|
407
|
+
const view = new DataView(buffer);
|
|
408
|
+
view.setBigUint64(0, bits, false);
|
|
409
|
+
return view.getFloat64(0, false);
|
|
410
|
+
}
|
|
411
|
+
countLeadingZeros64(value) {
|
|
412
|
+
if (value === 0n)
|
|
413
|
+
return 64;
|
|
414
|
+
let count = 0;
|
|
415
|
+
let mask = 1n << 63n;
|
|
416
|
+
while ((value & mask) === 0n && count < 64) {
|
|
417
|
+
count++;
|
|
418
|
+
mask >>= 1n;
|
|
419
|
+
}
|
|
420
|
+
return count;
|
|
421
|
+
}
|
|
422
|
+
countTrailingZeros64(value) {
|
|
423
|
+
if (value === 0n)
|
|
424
|
+
return 64;
|
|
425
|
+
let count = 0;
|
|
426
|
+
while ((value & 1n) === 0n && count < 64) {
|
|
427
|
+
count++;
|
|
428
|
+
value >>= 1n;
|
|
429
|
+
}
|
|
430
|
+
return count;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
// ============================================================================
|
|
434
|
+
// Delta-of-Delta Compression
|
|
435
|
+
// ============================================================================
|
|
436
|
+
/**
|
|
437
|
+
* Delta-of-delta compression for timestamps
|
|
438
|
+
*
|
|
439
|
+
* Stores first value, first delta, then delta-of-deltas using
|
|
440
|
+
* variable-bit encoding based on the Gorilla paper.
|
|
441
|
+
*/
|
|
442
|
+
class DeltaCodec {
|
|
443
|
+
encode(values) {
|
|
444
|
+
if (values.length === 0) {
|
|
445
|
+
return new Uint8Array([0, 0, 0, 0]);
|
|
446
|
+
}
|
|
447
|
+
// Header: length (4B) + first value (8B)
|
|
448
|
+
const headerSize = 4 + 8;
|
|
449
|
+
const writer = new BitWriter();
|
|
450
|
+
if (values.length === 1) {
|
|
451
|
+
const output = new Uint8Array(headerSize);
|
|
452
|
+
const view = new DataView(output.buffer);
|
|
453
|
+
view.setUint32(0, 1, true);
|
|
454
|
+
view.setBigInt64(4, BigInt(Math.round(values[0])), true);
|
|
455
|
+
return output;
|
|
456
|
+
}
|
|
457
|
+
// Calculate first delta
|
|
458
|
+
let prevValue = BigInt(Math.round(values[0]));
|
|
459
|
+
let prevDelta = BigInt(Math.round(values[1])) - prevValue;
|
|
460
|
+
// Write first delta using variable-bit encoding
|
|
461
|
+
this.writeDelta(writer, prevDelta);
|
|
462
|
+
// Encode delta-of-deltas
|
|
463
|
+
for (let i = 2; i < values.length; i++) {
|
|
464
|
+
const currentValue = BigInt(Math.round(values[i]));
|
|
465
|
+
const delta = currentValue - BigInt(Math.round(values[i - 1]));
|
|
466
|
+
const dod = delta - prevDelta;
|
|
467
|
+
this.writeDeltaOfDelta(writer, dod);
|
|
468
|
+
prevDelta = delta;
|
|
469
|
+
}
|
|
470
|
+
const dodBytes = writer.finish();
|
|
471
|
+
// Build output: [length 4B][first value 8B][dod bits...]
|
|
472
|
+
const output = new Uint8Array(headerSize + dodBytes.length);
|
|
473
|
+
const view = new DataView(output.buffer);
|
|
474
|
+
view.setUint32(0, values.length, true);
|
|
475
|
+
view.setBigInt64(4, BigInt(Math.round(values[0])), true);
|
|
476
|
+
output.set(dodBytes, headerSize);
|
|
477
|
+
return output;
|
|
478
|
+
}
|
|
479
|
+
decode(data) {
|
|
480
|
+
// Validate minimum buffer size for header
|
|
481
|
+
if (data.length < 4) {
|
|
482
|
+
if (data.length === 0)
|
|
483
|
+
return [];
|
|
484
|
+
throw new Error('Delta decode error: Buffer too small - expected at least 4 bytes for header');
|
|
485
|
+
}
|
|
486
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
487
|
+
const length = view.getUint32(0, true);
|
|
488
|
+
if (length === 0)
|
|
489
|
+
return [];
|
|
490
|
+
// Validate buffer has enough data for header (4 bytes) + first value (8 bytes)
|
|
491
|
+
if (data.length < 12) {
|
|
492
|
+
throw new Error('Delta decode error: Buffer truncated - insufficient data for first value');
|
|
493
|
+
}
|
|
494
|
+
// Sanity check: prevent unreasonable length values that could cause memory issues
|
|
495
|
+
if (length > 100_000_000) {
|
|
496
|
+
throw new Error(`Delta decode error: Invalid length ${length} - exceeds maximum allowed (100M values)`);
|
|
497
|
+
}
|
|
498
|
+
// Read first value
|
|
499
|
+
const firstValue = Number(view.getBigInt64(4, true));
|
|
500
|
+
const values = [firstValue];
|
|
501
|
+
if (length === 1)
|
|
502
|
+
return values;
|
|
503
|
+
const reader = new BitReader(data.slice(12));
|
|
504
|
+
// Read first delta
|
|
505
|
+
let prevDelta = this.readDelta(reader);
|
|
506
|
+
values.push(firstValue + Number(prevDelta));
|
|
507
|
+
if (length === 2)
|
|
508
|
+
return values;
|
|
509
|
+
// Read delta-of-deltas
|
|
510
|
+
for (let i = 2; i < length; i++) {
|
|
511
|
+
const dod = this.readDeltaOfDelta(reader);
|
|
512
|
+
const delta = prevDelta + dod;
|
|
513
|
+
values.push(values[values.length - 1] + Number(delta));
|
|
514
|
+
prevDelta = delta;
|
|
515
|
+
}
|
|
516
|
+
return values;
|
|
517
|
+
}
|
|
518
|
+
writeDelta(writer, delta) {
|
|
519
|
+
// Variable-bit encoding for first delta
|
|
520
|
+
// Use zigzag encoding then write with length prefix
|
|
521
|
+
const zigzag = delta >= 0n ? delta * 2n : -delta * 2n - 1n;
|
|
522
|
+
if (zigzag === 0n) {
|
|
523
|
+
writer.writeBit(false); // Single zero bit
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
writer.writeBit(true);
|
|
527
|
+
// Write the zigzag value with variable length
|
|
528
|
+
const bits = this.bitLength(zigzag);
|
|
529
|
+
writer.writeUint(bits, 6);
|
|
530
|
+
writer.writeBits(zigzag, bits);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
readDelta(reader) {
|
|
534
|
+
if (!reader.readBit()) {
|
|
535
|
+
return 0n;
|
|
536
|
+
}
|
|
537
|
+
const bits = reader.readUint(6);
|
|
538
|
+
const zigzag = reader.readBits(bits);
|
|
539
|
+
return (zigzag >> 1n) ^ -(zigzag & 1n);
|
|
540
|
+
}
|
|
541
|
+
writeDeltaOfDelta(writer, dod) {
|
|
542
|
+
// Encode delta-of-delta using variable-length encoding
|
|
543
|
+
// Similar to Gorilla: different bit counts for different ranges
|
|
544
|
+
// Use symmetric ranges around zero for easier decode
|
|
545
|
+
if (dod === 0n) {
|
|
546
|
+
// Single 0 bit
|
|
547
|
+
writer.writeBit(false);
|
|
548
|
+
}
|
|
549
|
+
else if (dod >= -64n && dod <= 63n) {
|
|
550
|
+
// '10' + 7 bits (symmetric range [-64, 63])
|
|
551
|
+
writer.writeBit(true);
|
|
552
|
+
writer.writeBit(false);
|
|
553
|
+
// Use zigzag encoding for clean symmetric handling
|
|
554
|
+
const zigzag = dod >= 0n ? dod * 2n : -dod * 2n - 1n;
|
|
555
|
+
writer.writeBits(zigzag, 7);
|
|
556
|
+
}
|
|
557
|
+
else if (dod >= -256n && dod <= 255n) {
|
|
558
|
+
// '110' + 9 bits (symmetric range [-256, 255])
|
|
559
|
+
writer.writeBit(true);
|
|
560
|
+
writer.writeBit(true);
|
|
561
|
+
writer.writeBit(false);
|
|
562
|
+
const zigzag = dod >= 0n ? dod * 2n : -dod * 2n - 1n;
|
|
563
|
+
writer.writeBits(zigzag, 9);
|
|
564
|
+
}
|
|
565
|
+
else if (dod >= -2048n && dod <= 2047n) {
|
|
566
|
+
// '1110' + 12 bits (symmetric range [-2048, 2047])
|
|
567
|
+
writer.writeBit(true);
|
|
568
|
+
writer.writeBit(true);
|
|
569
|
+
writer.writeBit(true);
|
|
570
|
+
writer.writeBit(false);
|
|
571
|
+
const zigzag = dod >= 0n ? dod * 2n : -dod * 2n - 1n;
|
|
572
|
+
writer.writeBits(zigzag, 12);
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
// '1111' + 64 bits for large deltas
|
|
576
|
+
writer.writeBit(true);
|
|
577
|
+
writer.writeBit(true);
|
|
578
|
+
writer.writeBit(true);
|
|
579
|
+
writer.writeBit(true);
|
|
580
|
+
// Zigzag encode for signed
|
|
581
|
+
const zigzag = dod >= 0n ? dod * 2n : -dod * 2n - 1n;
|
|
582
|
+
writer.writeBits(zigzag, 64);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
readDeltaOfDelta(reader) {
|
|
586
|
+
if (!reader.readBit()) {
|
|
587
|
+
return 0n;
|
|
588
|
+
}
|
|
589
|
+
if (!reader.readBit()) {
|
|
590
|
+
// 7 bits zigzag
|
|
591
|
+
const zigzag = reader.readBits(7);
|
|
592
|
+
return (zigzag >> 1n) ^ -(zigzag & 1n);
|
|
593
|
+
}
|
|
594
|
+
if (!reader.readBit()) {
|
|
595
|
+
// 9 bits zigzag
|
|
596
|
+
const zigzag = reader.readBits(9);
|
|
597
|
+
return (zigzag >> 1n) ^ -(zigzag & 1n);
|
|
598
|
+
}
|
|
599
|
+
if (!reader.readBit()) {
|
|
600
|
+
// 12 bits zigzag
|
|
601
|
+
const zigzag = reader.readBits(12);
|
|
602
|
+
return (zigzag >> 1n) ^ -(zigzag & 1n);
|
|
603
|
+
}
|
|
604
|
+
// 64 bits zigzag
|
|
605
|
+
const zigzag = reader.readBits(64);
|
|
606
|
+
return (zigzag >> 1n) ^ -(zigzag & 1n);
|
|
607
|
+
}
|
|
608
|
+
bitLength(value) {
|
|
609
|
+
if (value === 0n)
|
|
610
|
+
return 1;
|
|
611
|
+
let bits = 0;
|
|
612
|
+
let v = value;
|
|
613
|
+
while (v > 0n) {
|
|
614
|
+
bits++;
|
|
615
|
+
v >>= 1n;
|
|
616
|
+
}
|
|
617
|
+
return bits;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
// ============================================================================
|
|
621
|
+
// Run-Length Encoding
|
|
622
|
+
// ============================================================================
|
|
623
|
+
/**
|
|
624
|
+
* Run-length encoding for repeated values
|
|
625
|
+
*/
|
|
626
|
+
class RLECodec {
|
|
627
|
+
encode(values) {
|
|
628
|
+
if (values.length === 0) {
|
|
629
|
+
return new Uint8Array([0, 0, 0, 0]);
|
|
630
|
+
}
|
|
631
|
+
const runs = [];
|
|
632
|
+
let currentValue = values[0];
|
|
633
|
+
let currentCount = 1;
|
|
634
|
+
for (let i = 1; i < values.length; i++) {
|
|
635
|
+
if (values[i] === currentValue) {
|
|
636
|
+
currentCount++;
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
runs.push({ value: currentValue, count: currentCount });
|
|
640
|
+
currentValue = values[i];
|
|
641
|
+
currentCount = 1;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
runs.push({ value: currentValue, count: currentCount });
|
|
645
|
+
// Encode: [length 4B][numRuns 4B][run1Value 8B][run1Count 4B]...
|
|
646
|
+
const output = new Uint8Array(4 + 4 + runs.length * 12);
|
|
647
|
+
const view = new DataView(output.buffer);
|
|
648
|
+
view.setUint32(0, values.length, true); // Original length
|
|
649
|
+
view.setUint32(4, runs.length, true); // Number of runs
|
|
650
|
+
let offset = 8;
|
|
651
|
+
for (const run of runs) {
|
|
652
|
+
view.setFloat64(offset, run.value, true);
|
|
653
|
+
view.setUint32(offset + 8, run.count, true);
|
|
654
|
+
offset += 12;
|
|
655
|
+
}
|
|
656
|
+
return output;
|
|
657
|
+
}
|
|
658
|
+
decode(data) {
|
|
659
|
+
// Validate minimum buffer size for header
|
|
660
|
+
if (data.length < 4) {
|
|
661
|
+
if (data.length === 0)
|
|
662
|
+
return [];
|
|
663
|
+
throw new Error('RLE decode error: Buffer too small - expected at least 4 bytes for header');
|
|
664
|
+
}
|
|
665
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
666
|
+
const originalLength = view.getUint32(0, true);
|
|
667
|
+
if (originalLength === 0)
|
|
668
|
+
return [];
|
|
669
|
+
// Validate buffer has enough data for header (4 bytes) + numRuns (4 bytes)
|
|
670
|
+
if (data.length < 8) {
|
|
671
|
+
throw new Error('RLE decode error: Buffer truncated - insufficient data for run count');
|
|
672
|
+
}
|
|
673
|
+
// Sanity check: prevent unreasonable length values that could cause memory issues
|
|
674
|
+
if (originalLength > 100_000_000) {
|
|
675
|
+
throw new Error(`RLE decode error: Invalid original length ${originalLength} - exceeds maximum allowed (100M values)`);
|
|
676
|
+
}
|
|
677
|
+
const numRuns = view.getUint32(4, true);
|
|
678
|
+
// Sanity check: number of runs should be reasonable
|
|
679
|
+
if (numRuns > 100_000_000) {
|
|
680
|
+
throw new Error(`RLE decode error: Invalid number of runs ${numRuns} - exceeds maximum allowed (100M runs)`);
|
|
681
|
+
}
|
|
682
|
+
// Validate buffer has enough data for all runs (each run is 12 bytes: 8B value + 4B count)
|
|
683
|
+
const expectedDataSize = 8 + numRuns * 12;
|
|
684
|
+
if (data.length < expectedDataSize) {
|
|
685
|
+
throw new Error(`RLE decode error: Buffer truncated - expected ${expectedDataSize} bytes for ${numRuns} runs, got ${data.length}`);
|
|
686
|
+
}
|
|
687
|
+
const values = [];
|
|
688
|
+
let offset = 8;
|
|
689
|
+
let totalCount = 0;
|
|
690
|
+
for (let i = 0; i < numRuns; i++) {
|
|
691
|
+
const value = view.getFloat64(offset, true);
|
|
692
|
+
const count = view.getUint32(offset + 8, true);
|
|
693
|
+
offset += 12;
|
|
694
|
+
// Validate individual run count
|
|
695
|
+
if (count > 100_000_000) {
|
|
696
|
+
throw new Error(`RLE decode error: Invalid run count ${count} at run ${i} - exceeds maximum allowed`);
|
|
697
|
+
}
|
|
698
|
+
totalCount += count;
|
|
699
|
+
// Check for overflow or mismatch
|
|
700
|
+
if (totalCount > originalLength) {
|
|
701
|
+
throw new Error(`RLE decode error: Run data exceeds declared original length (${totalCount} > ${originalLength})`);
|
|
702
|
+
}
|
|
703
|
+
for (let j = 0; j < count; j++) {
|
|
704
|
+
values.push(value);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return values;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
// ============================================================================
|
|
711
|
+
// ZSTD-like Compression (using simple LZ77 + Huffman-like approach)
|
|
712
|
+
// ============================================================================
|
|
713
|
+
/**
|
|
714
|
+
* General-purpose compression using deflate-like algorithm
|
|
715
|
+
*/
|
|
716
|
+
class ZstdCodec {
|
|
717
|
+
encode(values) {
|
|
718
|
+
if (values.length === 0) {
|
|
719
|
+
return new Uint8Array([0, 0, 0, 0]);
|
|
720
|
+
}
|
|
721
|
+
// Convert values to bytes
|
|
722
|
+
const rawBytes = new Uint8Array(values.length * 8);
|
|
723
|
+
const view = new DataView(rawBytes.buffer);
|
|
724
|
+
for (let i = 0; i < values.length; i++) {
|
|
725
|
+
view.setFloat64(i * 8, values[i], true);
|
|
726
|
+
}
|
|
727
|
+
// Simple compression: store raw with header
|
|
728
|
+
// Format: [length 4B][compressedLength 4B][compressed data]
|
|
729
|
+
const compressed = this.compress(rawBytes);
|
|
730
|
+
const output = new Uint8Array(8 + compressed.length);
|
|
731
|
+
const outView = new DataView(output.buffer);
|
|
732
|
+
outView.setUint32(0, values.length, true);
|
|
733
|
+
outView.setUint32(4, compressed.length, true);
|
|
734
|
+
output.set(compressed, 8);
|
|
735
|
+
return output;
|
|
736
|
+
}
|
|
737
|
+
decode(data) {
|
|
738
|
+
// Validate minimum buffer size for length field
|
|
739
|
+
if (data.length < 4) {
|
|
740
|
+
if (data.length === 0)
|
|
741
|
+
return [];
|
|
742
|
+
throw new Error('ZSTD decode error: Buffer too small - expected at least 4 bytes for header');
|
|
743
|
+
}
|
|
744
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
745
|
+
const length = view.getUint32(0, true);
|
|
746
|
+
// Empty array case - encoder outputs only 4 bytes with length=0
|
|
747
|
+
if (length === 0)
|
|
748
|
+
return [];
|
|
749
|
+
// For non-empty data, we need the full header (8 bytes)
|
|
750
|
+
if (data.length < 8) {
|
|
751
|
+
throw new Error('ZSTD decode error: Buffer truncated - insufficient data for compressed length field');
|
|
752
|
+
}
|
|
753
|
+
// Sanity check: prevent unreasonable length values that could cause memory issues
|
|
754
|
+
if (length > 100_000_000) {
|
|
755
|
+
throw new Error(`ZSTD decode error: Invalid length ${length} - exceeds maximum allowed (100M values)`);
|
|
756
|
+
}
|
|
757
|
+
const compressedLength = view.getUint32(4, true);
|
|
758
|
+
// Validate compressed length is reasonable
|
|
759
|
+
if (compressedLength > data.length - 8) {
|
|
760
|
+
throw new Error(`ZSTD decode error: Buffer truncated - compressed length ${compressedLength} exceeds available data ${data.length - 8}`);
|
|
761
|
+
}
|
|
762
|
+
// Sanity check: compressed data should not claim to be larger than possible
|
|
763
|
+
if (compressedLength > 1_000_000_000) {
|
|
764
|
+
throw new Error(`ZSTD decode error: Invalid compressed length ${compressedLength} - exceeds maximum allowed`);
|
|
765
|
+
}
|
|
766
|
+
const compressed = data.slice(8, 8 + compressedLength);
|
|
767
|
+
const decompressed = this.decompress(compressed, length * 8);
|
|
768
|
+
// Validate decompressed data is correct size
|
|
769
|
+
if (decompressed.length < length * 8) {
|
|
770
|
+
throw new Error(`ZSTD decode error: Decompressed data size mismatch - expected ${length * 8} bytes, got ${decompressed.length}`);
|
|
771
|
+
}
|
|
772
|
+
const decompView = new DataView(decompressed.buffer, decompressed.byteOffset, decompressed.byteLength);
|
|
773
|
+
const values = [];
|
|
774
|
+
for (let i = 0; i < length; i++) {
|
|
775
|
+
values.push(decompView.getFloat64(i * 8, true));
|
|
776
|
+
}
|
|
777
|
+
return values;
|
|
778
|
+
}
|
|
779
|
+
compress(data) {
|
|
780
|
+
// Simple RLE-like compression for byte sequences
|
|
781
|
+
const output = [];
|
|
782
|
+
let i = 0;
|
|
783
|
+
while (i < data.length) {
|
|
784
|
+
// Look for runs of identical bytes
|
|
785
|
+
let runLength = 1;
|
|
786
|
+
while (i + runLength < data.length && data[i + runLength] === data[i] && runLength < 127) {
|
|
787
|
+
runLength++;
|
|
788
|
+
}
|
|
789
|
+
if (runLength >= 4) {
|
|
790
|
+
// Encode run: [0x80 | length, value]
|
|
791
|
+
output.push(0x80 | runLength);
|
|
792
|
+
output.push(data[i]);
|
|
793
|
+
i += runLength;
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
// Find literal run
|
|
797
|
+
const literalStart = i;
|
|
798
|
+
let literalLength = 0;
|
|
799
|
+
while (i < data.length && literalLength < 127) {
|
|
800
|
+
// Check if next bytes form a run worth encoding
|
|
801
|
+
let nextRunLength = 1;
|
|
802
|
+
while (i + nextRunLength < data.length &&
|
|
803
|
+
data[i + nextRunLength] === data[i] &&
|
|
804
|
+
nextRunLength < 127) {
|
|
805
|
+
nextRunLength++;
|
|
806
|
+
}
|
|
807
|
+
if (nextRunLength >= 4)
|
|
808
|
+
break;
|
|
809
|
+
literalLength++;
|
|
810
|
+
i++;
|
|
811
|
+
}
|
|
812
|
+
if (literalLength > 0) {
|
|
813
|
+
output.push(literalLength);
|
|
814
|
+
for (let j = 0; j < literalLength; j++) {
|
|
815
|
+
output.push(data[literalStart + j]);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return new Uint8Array(output);
|
|
821
|
+
}
|
|
822
|
+
decompress(data, expectedLength) {
|
|
823
|
+
const output = new Uint8Array(expectedLength);
|
|
824
|
+
let outPos = 0;
|
|
825
|
+
let inPos = 0;
|
|
826
|
+
while (inPos < data.length && outPos < expectedLength) {
|
|
827
|
+
const header = data[inPos++];
|
|
828
|
+
if (header & 0x80) {
|
|
829
|
+
// Run
|
|
830
|
+
const length = header & 0x7f;
|
|
831
|
+
const value = data[inPos++];
|
|
832
|
+
for (let i = 0; i < length && outPos < expectedLength; i++) {
|
|
833
|
+
output[outPos++] = value;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
else {
|
|
837
|
+
// Literals
|
|
838
|
+
const length = header;
|
|
839
|
+
for (let i = 0; i < length && inPos < data.length && outPos < expectedLength; i++) {
|
|
840
|
+
output[outPos++] = data[inPos++];
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return output;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
// ============================================================================
|
|
848
|
+
// Helper functions for large arrays (avoid stack overflow)
|
|
849
|
+
// ============================================================================
|
|
850
|
+
function arrayMin(values) {
|
|
851
|
+
if (values.length === 0)
|
|
852
|
+
return Infinity;
|
|
853
|
+
let min = values[0];
|
|
854
|
+
for (let i = 1; i < values.length; i++) {
|
|
855
|
+
if (values[i] < min)
|
|
856
|
+
min = values[i];
|
|
857
|
+
}
|
|
858
|
+
return min;
|
|
859
|
+
}
|
|
860
|
+
function arrayMax(values) {
|
|
861
|
+
if (values.length === 0)
|
|
862
|
+
return -Infinity;
|
|
863
|
+
let max = values[0];
|
|
864
|
+
for (let i = 1; i < values.length; i++) {
|
|
865
|
+
if (values[i] > max)
|
|
866
|
+
max = values[i];
|
|
867
|
+
}
|
|
868
|
+
return max;
|
|
869
|
+
}
|
|
870
|
+
function arraySum(values) {
|
|
871
|
+
let sum = 0;
|
|
872
|
+
for (let i = 0; i < values.length; i++) {
|
|
873
|
+
sum += values[i];
|
|
874
|
+
}
|
|
875
|
+
return sum;
|
|
876
|
+
}
|
|
877
|
+
// ============================================================================
|
|
878
|
+
// Type Guards
|
|
879
|
+
// ============================================================================
|
|
880
|
+
/**
|
|
881
|
+
* Check if a column type is numeric (can be aggregated)
|
|
882
|
+
*/
|
|
883
|
+
function isNumericColumnType(type) {
|
|
884
|
+
return type === 'int64' || type === 'float64' || type === 'timestamp';
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Check if a column type is comparable (supports ordering operators)
|
|
888
|
+
*/
|
|
889
|
+
function isComparableColumnType(type) {
|
|
890
|
+
return type === 'int64' || type === 'float64' || type === 'timestamp' || type === 'string';
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Check if a column type supports bloom filter/HLL operations
|
|
894
|
+
*/
|
|
895
|
+
function isHashableColumnType(type) {
|
|
896
|
+
return type === 'int64' || type === 'float64' || type === 'string' || type === 'timestamp';
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Runtime check that a value is a number
|
|
900
|
+
*/
|
|
901
|
+
function isNumber(value) {
|
|
902
|
+
return typeof value === 'number';
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Runtime check that a value is a string
|
|
906
|
+
*/
|
|
907
|
+
function isString(value) {
|
|
908
|
+
return typeof value === 'string';
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Runtime check that a value is number or string (for bloom filter/HLL)
|
|
912
|
+
*/
|
|
913
|
+
function isNumberOrString(value) {
|
|
914
|
+
return typeof value === 'number' || typeof value === 'string';
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Runtime check that a value is an array
|
|
918
|
+
*/
|
|
919
|
+
function isArray(value) {
|
|
920
|
+
return Array.isArray(value);
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Runtime check that a value is a [number, number] tuple
|
|
924
|
+
*/
|
|
925
|
+
function isNumberTuple(value) {
|
|
926
|
+
return Array.isArray(value) && value.length === 2 && isNumber(value[0]) && isNumber(value[1]);
|
|
927
|
+
}
|
|
928
|
+
class ColumnStoreImpl {
|
|
929
|
+
columns = new Map();
|
|
930
|
+
gorillaCodec = new GorillaCodec();
|
|
931
|
+
deltaCodec = new DeltaCodec();
|
|
932
|
+
rleCodec = new RLECodec();
|
|
933
|
+
zstdCodec = new ZstdCodec();
|
|
934
|
+
// Compression codecs
|
|
935
|
+
encode(values, codec) {
|
|
936
|
+
switch (codec) {
|
|
937
|
+
case 'gorilla':
|
|
938
|
+
return this.gorillaCodec.encode(values);
|
|
939
|
+
case 'delta':
|
|
940
|
+
return this.deltaCodec.encode(values);
|
|
941
|
+
case 'rle':
|
|
942
|
+
return this.rleCodec.encode(values);
|
|
943
|
+
case 'zstd':
|
|
944
|
+
return this.zstdCodec.encode(values);
|
|
945
|
+
default:
|
|
946
|
+
throw new Error(`Unknown codec: ${codec}`);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
decode(data, codec) {
|
|
950
|
+
switch (codec) {
|
|
951
|
+
case 'gorilla':
|
|
952
|
+
return this.gorillaCodec.decode(data);
|
|
953
|
+
case 'delta':
|
|
954
|
+
return this.deltaCodec.decode(data);
|
|
955
|
+
case 'rle':
|
|
956
|
+
return this.rleCodec.decode(data);
|
|
957
|
+
case 'zstd':
|
|
958
|
+
return this.zstdCodec.decode(data);
|
|
959
|
+
default:
|
|
960
|
+
throw new Error(`Unknown codec: ${codec}`);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
// Column operations
|
|
964
|
+
addColumn(name, type) {
|
|
965
|
+
if (this.columns.has(name)) {
|
|
966
|
+
throw new Error(`Column '${name}' already exists`);
|
|
967
|
+
}
|
|
968
|
+
this.columns.set(name, { type, data: [] });
|
|
969
|
+
}
|
|
970
|
+
append(column, values) {
|
|
971
|
+
const col = this.columns.get(column);
|
|
972
|
+
if (!col) {
|
|
973
|
+
throw new Error(`Column '${column}' does not exist`);
|
|
974
|
+
}
|
|
975
|
+
// Validate type compatibility
|
|
976
|
+
for (const value of values) {
|
|
977
|
+
if (!this.isValidType(value, col.type)) {
|
|
978
|
+
throw new Error(`Invalid value type for column '${column}' (expected ${col.type})`);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
// Use push.apply in chunks to avoid stack overflow for large arrays
|
|
982
|
+
const CHUNK_SIZE = 10000;
|
|
983
|
+
for (let i = 0; i < values.length; i += CHUNK_SIZE) {
|
|
984
|
+
const chunk = values.slice(i, i + CHUNK_SIZE);
|
|
985
|
+
col.data.push(...chunk);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
project(columns) {
|
|
989
|
+
const result = new Map();
|
|
990
|
+
let rowCount = 0;
|
|
991
|
+
for (const colName of columns) {
|
|
992
|
+
const col = this.columns.get(colName);
|
|
993
|
+
if (!col) {
|
|
994
|
+
throw new Error(`Column '${colName}' does not exist`);
|
|
995
|
+
}
|
|
996
|
+
result.set(colName, [...col.data]);
|
|
997
|
+
rowCount = col.data.length;
|
|
998
|
+
}
|
|
999
|
+
return { columns: result, rowCount };
|
|
1000
|
+
}
|
|
1001
|
+
filter(predicate) {
|
|
1002
|
+
const col = this.columns.get(predicate.column);
|
|
1003
|
+
if (!col) {
|
|
1004
|
+
throw new Error(`Column '${predicate.column}' does not exist`);
|
|
1005
|
+
}
|
|
1006
|
+
// Find matching row indices
|
|
1007
|
+
const matchingIndices = [];
|
|
1008
|
+
for (let i = 0; i < col.data.length; i++) {
|
|
1009
|
+
if (this.evaluatePredicate(col.data[i], predicate, col.type)) {
|
|
1010
|
+
matchingIndices.push(i);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
// Project all columns at matching indices
|
|
1014
|
+
const result = new Map();
|
|
1015
|
+
for (const [colName, colInfo] of this.columns) {
|
|
1016
|
+
const filtered = matchingIndices.map((i) => colInfo.data[i]);
|
|
1017
|
+
result.set(colName, filtered);
|
|
1018
|
+
}
|
|
1019
|
+
return { columns: result, rowCount: matchingIndices.length };
|
|
1020
|
+
}
|
|
1021
|
+
aggregate(column, fn) {
|
|
1022
|
+
const col = this.columns.get(column);
|
|
1023
|
+
if (!col) {
|
|
1024
|
+
throw new Error(`Column '${column}' does not exist`);
|
|
1025
|
+
}
|
|
1026
|
+
// Validate that column type is numeric before aggregation
|
|
1027
|
+
if (!isNumericColumnType(col.type)) {
|
|
1028
|
+
throw new Error(`Cannot aggregate non-numeric column '${column}' (type: ${col.type})`);
|
|
1029
|
+
}
|
|
1030
|
+
// Now we know the column contains numbers, validate at runtime for safety
|
|
1031
|
+
const values = [];
|
|
1032
|
+
for (const value of col.data) {
|
|
1033
|
+
if (!isNumber(value)) {
|
|
1034
|
+
throw new Error(`Invalid value in numeric column '${column}': expected number, got ${typeof value}`);
|
|
1035
|
+
}
|
|
1036
|
+
values.push(value);
|
|
1037
|
+
}
|
|
1038
|
+
switch (fn) {
|
|
1039
|
+
case 'count':
|
|
1040
|
+
return values.length;
|
|
1041
|
+
case 'sum':
|
|
1042
|
+
return arraySum(values);
|
|
1043
|
+
case 'min':
|
|
1044
|
+
return arrayMin(values);
|
|
1045
|
+
case 'max':
|
|
1046
|
+
return arrayMax(values);
|
|
1047
|
+
case 'avg':
|
|
1048
|
+
if (values.length === 0)
|
|
1049
|
+
return NaN;
|
|
1050
|
+
return arraySum(values) / values.length;
|
|
1051
|
+
default:
|
|
1052
|
+
throw new Error(`Unknown aggregate function: ${fn}`);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
// Statistics
|
|
1056
|
+
minMax(column) {
|
|
1057
|
+
const col = this.columns.get(column);
|
|
1058
|
+
if (!col) {
|
|
1059
|
+
throw new Error(`Column '${column}' does not exist`);
|
|
1060
|
+
}
|
|
1061
|
+
// Validate that column type is numeric
|
|
1062
|
+
if (!isNumericColumnType(col.type)) {
|
|
1063
|
+
throw new Error(`Cannot compute minMax on non-numeric column '${column}' (type: ${col.type})`);
|
|
1064
|
+
}
|
|
1065
|
+
if (col.data.length === 0) {
|
|
1066
|
+
throw new Error(`Column '${column}' is empty`);
|
|
1067
|
+
}
|
|
1068
|
+
// Validate and extract numeric values
|
|
1069
|
+
const values = [];
|
|
1070
|
+
for (const value of col.data) {
|
|
1071
|
+
if (!isNumber(value)) {
|
|
1072
|
+
throw new Error(`Invalid value in numeric column '${column}': expected number, got ${typeof value}`);
|
|
1073
|
+
}
|
|
1074
|
+
values.push(value);
|
|
1075
|
+
}
|
|
1076
|
+
return {
|
|
1077
|
+
min: arrayMin(values),
|
|
1078
|
+
max: arrayMax(values),
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
distinctCount(column) {
|
|
1082
|
+
const col = this.columns.get(column);
|
|
1083
|
+
if (!col) {
|
|
1084
|
+
throw new Error(`Column '${column}' does not exist`);
|
|
1085
|
+
}
|
|
1086
|
+
// Validate that column type supports hashing
|
|
1087
|
+
if (!isHashableColumnType(col.type)) {
|
|
1088
|
+
throw new Error(`Cannot compute distinctCount on column '${column}' (type: ${col.type})`);
|
|
1089
|
+
}
|
|
1090
|
+
const values = col.data;
|
|
1091
|
+
if (values.length === 0)
|
|
1092
|
+
return 0;
|
|
1093
|
+
// For small datasets, use exact count
|
|
1094
|
+
if (values.length < 10000) {
|
|
1095
|
+
return new Set(values.map((v) => String(v))).size;
|
|
1096
|
+
}
|
|
1097
|
+
// For large datasets, use HyperLogLog
|
|
1098
|
+
const hll = new HyperLogLog(14);
|
|
1099
|
+
for (const value of values) {
|
|
1100
|
+
// Validate each value at runtime
|
|
1101
|
+
if (!isNumberOrString(value)) {
|
|
1102
|
+
throw new Error(`Invalid value in column '${column}': expected number or string, got ${typeof value}`);
|
|
1103
|
+
}
|
|
1104
|
+
hll.add(value);
|
|
1105
|
+
}
|
|
1106
|
+
return Math.round(hll.estimate());
|
|
1107
|
+
}
|
|
1108
|
+
bloomFilter(column) {
|
|
1109
|
+
const col = this.columns.get(column);
|
|
1110
|
+
if (!col) {
|
|
1111
|
+
throw new Error(`Column '${column}' does not exist`);
|
|
1112
|
+
}
|
|
1113
|
+
// Validate that column type supports hashing
|
|
1114
|
+
if (!isHashableColumnType(col.type)) {
|
|
1115
|
+
throw new Error(`Cannot create bloom filter for column '${column}' (type: ${col.type})`);
|
|
1116
|
+
}
|
|
1117
|
+
// Create bloom filter with very low FPR for safety
|
|
1118
|
+
const bloom = new BloomFilterImpl(Math.max(col.data.length, 100), 0.005);
|
|
1119
|
+
for (const value of col.data) {
|
|
1120
|
+
// Validate each value at runtime
|
|
1121
|
+
if (!isNumberOrString(value)) {
|
|
1122
|
+
throw new Error(`Invalid value in column '${column}': expected number or string, got ${typeof value}`);
|
|
1123
|
+
}
|
|
1124
|
+
bloom.add(value);
|
|
1125
|
+
}
|
|
1126
|
+
return bloom;
|
|
1127
|
+
}
|
|
1128
|
+
// Helper methods
|
|
1129
|
+
isValidType(value, type) {
|
|
1130
|
+
switch (type) {
|
|
1131
|
+
case 'int64':
|
|
1132
|
+
case 'float64':
|
|
1133
|
+
case 'timestamp':
|
|
1134
|
+
return typeof value === 'number';
|
|
1135
|
+
case 'string':
|
|
1136
|
+
return typeof value === 'string';
|
|
1137
|
+
case 'boolean':
|
|
1138
|
+
return typeof value === 'boolean';
|
|
1139
|
+
default:
|
|
1140
|
+
return false;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
evaluatePredicate(value, predicate, columnType) {
|
|
1144
|
+
const { op, value: predicateValue } = predicate;
|
|
1145
|
+
switch (op) {
|
|
1146
|
+
case '=':
|
|
1147
|
+
return value === predicateValue;
|
|
1148
|
+
case '!=':
|
|
1149
|
+
return value !== predicateValue;
|
|
1150
|
+
case '>':
|
|
1151
|
+
case '<':
|
|
1152
|
+
case '>=':
|
|
1153
|
+
case '<=': {
|
|
1154
|
+
// Validate that both value and predicate are comparable
|
|
1155
|
+
if (!isComparableColumnType(columnType)) {
|
|
1156
|
+
throw new Error(`Cannot use comparison operator '${op}' on non-comparable column type '${columnType}'`);
|
|
1157
|
+
}
|
|
1158
|
+
// For numeric types, validate both operands are numbers
|
|
1159
|
+
if (columnType === 'int64' || columnType === 'float64' || columnType === 'timestamp') {
|
|
1160
|
+
if (!isNumber(value)) {
|
|
1161
|
+
throw new Error(`Invalid column value for comparison: expected number, got ${typeof value}`);
|
|
1162
|
+
}
|
|
1163
|
+
if (!isNumber(predicateValue)) {
|
|
1164
|
+
throw new Error(`Invalid predicate value for comparison: expected number, got ${typeof predicateValue}`);
|
|
1165
|
+
}
|
|
1166
|
+
switch (op) {
|
|
1167
|
+
case '>': return value > predicateValue;
|
|
1168
|
+
case '<': return value < predicateValue;
|
|
1169
|
+
case '>=': return value >= predicateValue;
|
|
1170
|
+
case '<=': return value <= predicateValue;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
// For string type, validate both operands are strings
|
|
1174
|
+
if (columnType === 'string') {
|
|
1175
|
+
if (!isString(value)) {
|
|
1176
|
+
throw new Error(`Invalid column value for comparison: expected string, got ${typeof value}`);
|
|
1177
|
+
}
|
|
1178
|
+
if (!isString(predicateValue)) {
|
|
1179
|
+
throw new Error(`Invalid predicate value for comparison: expected string, got ${typeof predicateValue}`);
|
|
1180
|
+
}
|
|
1181
|
+
switch (op) {
|
|
1182
|
+
case '>': return value > predicateValue;
|
|
1183
|
+
case '<': return value < predicateValue;
|
|
1184
|
+
case '>=': return value >= predicateValue;
|
|
1185
|
+
case '<=': return value <= predicateValue;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
case 'in': {
|
|
1191
|
+
// Validate that predicateValue is an array
|
|
1192
|
+
if (!isArray(predicateValue)) {
|
|
1193
|
+
throw new Error(`Invalid predicate value for 'in' operator: expected array, got ${typeof predicateValue}`);
|
|
1194
|
+
}
|
|
1195
|
+
return predicateValue.includes(value);
|
|
1196
|
+
}
|
|
1197
|
+
case 'between': {
|
|
1198
|
+
// Validate that column type is numeric
|
|
1199
|
+
if (columnType !== 'int64' && columnType !== 'float64' && columnType !== 'timestamp') {
|
|
1200
|
+
throw new Error(`Cannot use 'between' operator on non-numeric column type '${columnType}'`);
|
|
1201
|
+
}
|
|
1202
|
+
// Validate predicate value is [number, number] tuple
|
|
1203
|
+
if (!isNumberTuple(predicateValue)) {
|
|
1204
|
+
throw new Error(`Invalid predicate value for 'between' operator: expected [number, number], got ${typeof predicateValue}`);
|
|
1205
|
+
}
|
|
1206
|
+
// Validate column value is number
|
|
1207
|
+
if (!isNumber(value)) {
|
|
1208
|
+
throw new Error(`Invalid column value for 'between' comparison: expected number, got ${typeof value}`);
|
|
1209
|
+
}
|
|
1210
|
+
const [min, max] = predicateValue;
|
|
1211
|
+
return value >= min && value <= max;
|
|
1212
|
+
}
|
|
1213
|
+
default:
|
|
1214
|
+
return false;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
// ============================================================================
|
|
1219
|
+
// Factory Function
|
|
1220
|
+
// ============================================================================
|
|
1221
|
+
/**
|
|
1222
|
+
* Create a new TypedColumnStore instance
|
|
1223
|
+
*/
|
|
1224
|
+
export function createColumnStore() {
|
|
1225
|
+
return new ColumnStoreImpl();
|
|
1226
|
+
}
|
|
1227
|
+
// Re-export the TypedColumnStore class for type purposes
|
|
1228
|
+
export { ColumnStoreImpl as TypedColumnStoreClass };
|
|
1229
|
+
//# sourceMappingURL=typed-column-store.js.map
|