dotdo 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +446 -315
- package/cli/README.md +238 -0
- package/cli/agent.ts +72 -0
- package/cli/bin.js +44 -0
- package/cli/bin.ts +38 -0
- package/cli/build.ts +157 -0
- package/cli/commands/auth/login.ts +14 -0
- package/cli/commands/auth/logout.ts +6 -0
- package/cli/commands/auth/whoami.ts +16 -0
- package/cli/commands/deploy-multi.ts +245 -0
- package/cli/commands/dev/deploy.ts +100 -0
- package/cli/commands/dev/dev.ts +95 -0
- package/cli/commands/dev/logs.ts +91 -0
- package/cli/commands/dev-local.ts +88 -0
- package/cli/commands/do-ops.ts +314 -0
- package/cli/commands/index.ts +100 -0
- package/cli/commands/init.ts +247 -0
- package/cli/commands/introspect/emitter.ts +315 -0
- package/cli/commands/introspect/index.ts +193 -0
- package/cli/commands/link.ts +598 -0
- package/cli/commands/snippets.ts +415 -0
- package/cli/commands/tunnel.ts +239 -0
- package/cli/device-auth.ts +289 -0
- package/cli/fallback.ts +12 -0
- package/cli/index.ts +121 -0
- package/cli/main.ts +246 -0
- package/cli/mcp-stdio.ts +790 -0
- package/cli/package.json +62 -0
- package/cli/runtime/do-registry.ts +193 -0
- package/cli/runtime/embedded-db.ts +344 -0
- package/cli/runtime/index.ts +9 -0
- package/cli/runtime/miniflare-adapter.ts +162 -0
- package/cli/sandbox.ts +82 -0
- package/cli/src/args.ts +174 -0
- package/cli/src/auth.ts +55 -0
- package/cli/src/commands/call.ts +84 -0
- package/cli/src/commands/charge.ts +96 -0
- package/cli/src/commands/config.ts +115 -0
- package/cli/src/commands/email.ts +112 -0
- package/cli/src/commands/llm.ts +115 -0
- package/cli/src/commands/queue.ts +134 -0
- package/cli/src/commands/text.ts +86 -0
- package/cli/src/config.ts +185 -0
- package/cli/src/output.ts +246 -0
- package/cli/src/rpc.ts +192 -0
- package/cli/utils/config.ts +282 -0
- package/cli/utils/detect.ts +73 -0
- package/cli/utils/index.ts +15 -0
- package/cli/utils/logger.ts +232 -0
- 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/middleware/auth-federation.js +573 -0
- package/dist/api/middleware/auth-federation.js.map +1 -0
- package/dist/api/middleware/auth.js +545 -0
- package/dist/api/middleware/auth.js.map +1 -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 +116 -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/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/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 +753 -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 +1006 -0
- package/dist/lib/mixins/git.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 +1190 -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/DOCache.js +153 -0
- package/dist/objects/DOCache.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 +650 -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 +691 -0
- package/dist/objects/transport/mcp-server.js.map +1 -0
- package/dist/objects/transport/rest-autowire.js +1508 -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 +1539 -0
- package/dist/objects/transport/rpc-server.js.map +1 -0
- package/dist/objects/transport/shared.js +576 -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/sandbox/index.js +258 -0
- package/dist/sandbox/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 +1149 -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 +146 -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 +294 -46
|
@@ -0,0 +1,832 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifact Ingest Snippet
|
|
3
|
+
*
|
|
4
|
+
* Handles artifact ingestion via JSONL for the artifact storage system.
|
|
5
|
+
* Parses JSONL bodies, validates schema, chunks large payloads, and routes
|
|
6
|
+
* to the appropriate Pipeline based on X-Artifact-Mode header.
|
|
7
|
+
*
|
|
8
|
+
* Constraints:
|
|
9
|
+
* - Snippet size: <32KB
|
|
10
|
+
* - CPU time: <5ms
|
|
11
|
+
* - Chunk size: <=1MB batches for Pipeline HTTP endpoint
|
|
12
|
+
*
|
|
13
|
+
* @module snippets/artifacts-ingest
|
|
14
|
+
* @see docs/plans/2026-01-10-artifact-storage-design.md
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Default console-based metrics implementation.
|
|
18
|
+
* Outputs structured JSON logs for monitoring.
|
|
19
|
+
*/
|
|
20
|
+
export function createDefaultMetrics() {
|
|
21
|
+
const ts = () => new Date().toISOString();
|
|
22
|
+
return {
|
|
23
|
+
recordMetric(name, value, tags) {
|
|
24
|
+
console.log(JSON.stringify({
|
|
25
|
+
type: 'metric',
|
|
26
|
+
name,
|
|
27
|
+
value,
|
|
28
|
+
tags,
|
|
29
|
+
ts: ts(),
|
|
30
|
+
}));
|
|
31
|
+
},
|
|
32
|
+
recordLatency(name, durationMs, tags) {
|
|
33
|
+
console.log(JSON.stringify({
|
|
34
|
+
type: 'latency',
|
|
35
|
+
name,
|
|
36
|
+
durationMs,
|
|
37
|
+
tags,
|
|
38
|
+
ts: ts(),
|
|
39
|
+
}));
|
|
40
|
+
},
|
|
41
|
+
recordError(name, error, tags) {
|
|
42
|
+
console.log(JSON.stringify({
|
|
43
|
+
type: 'error',
|
|
44
|
+
name,
|
|
45
|
+
message: error.message,
|
|
46
|
+
tags,
|
|
47
|
+
ts: ts(),
|
|
48
|
+
}));
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* No-op metrics implementation for when metrics are disabled.
|
|
54
|
+
*/
|
|
55
|
+
export const noopMetrics = {
|
|
56
|
+
recordMetric() { },
|
|
57
|
+
recordLatency() { },
|
|
58
|
+
recordError() { },
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Sleep utility for delays between retries.
|
|
62
|
+
*/
|
|
63
|
+
function sleep(ms) {
|
|
64
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Executes a function with exponential backoff retry logic.
|
|
68
|
+
*
|
|
69
|
+
* @param fn - The async function to execute
|
|
70
|
+
* @param options - Retry configuration options
|
|
71
|
+
* @returns Promise resolving to the result with retry metadata
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const result = await withRetry(
|
|
76
|
+
* () => fetch(url),
|
|
77
|
+
* { maxRetries: 3, baseDelayMs: 100 }
|
|
78
|
+
* )
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export async function withRetry(fn, options) {
|
|
82
|
+
const maxRetries = options?.maxRetries ?? 3;
|
|
83
|
+
const baseDelayMs = options?.baseDelayMs ?? 100;
|
|
84
|
+
const maxDelayMs = options?.maxDelayMs ?? 1000;
|
|
85
|
+
let lastError;
|
|
86
|
+
let retryCount = 0;
|
|
87
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
88
|
+
try {
|
|
89
|
+
const result = await fn();
|
|
90
|
+
return {
|
|
91
|
+
result,
|
|
92
|
+
retries: retryCount,
|
|
93
|
+
success: true,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
98
|
+
if (attempt < maxRetries) {
|
|
99
|
+
retryCount++;
|
|
100
|
+
// Exponential backoff: baseDelayMs * 2^attempt, capped at maxDelayMs
|
|
101
|
+
const delay = Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
102
|
+
await sleep(delay);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
result: undefined,
|
|
108
|
+
retries: retryCount,
|
|
109
|
+
success: false,
|
|
110
|
+
error: lastError?.message ?? 'Unknown error',
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// ============================================================================
|
|
114
|
+
// JSONL Parsing
|
|
115
|
+
// ============================================================================
|
|
116
|
+
/**
|
|
117
|
+
* Parses a JSONL stream and yields individual records.
|
|
118
|
+
* Handles records split across stream chunks.
|
|
119
|
+
*
|
|
120
|
+
* @param body - ReadableStream of JSONL data
|
|
121
|
+
* @yields Parsed objects from each line
|
|
122
|
+
* @throws {Error} When a line contains malformed JSON
|
|
123
|
+
*/
|
|
124
|
+
export async function* parseJSONL(body) {
|
|
125
|
+
const reader = body.getReader();
|
|
126
|
+
const decoder = new TextDecoder();
|
|
127
|
+
let buffer = '';
|
|
128
|
+
try {
|
|
129
|
+
while (true) {
|
|
130
|
+
const { done, value } = await reader.read();
|
|
131
|
+
if (done) {
|
|
132
|
+
// Process any remaining content in buffer
|
|
133
|
+
if (buffer.trim()) {
|
|
134
|
+
yield JSON.parse(buffer.trim());
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
buffer += decoder.decode(value, { stream: true });
|
|
139
|
+
// Process complete lines
|
|
140
|
+
let newlineIndex;
|
|
141
|
+
while ((newlineIndex = buffer.indexOf('\n')) !== -1) {
|
|
142
|
+
const line = buffer.slice(0, newlineIndex).trim();
|
|
143
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
144
|
+
if (line) {
|
|
145
|
+
yield JSON.parse(line);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
reader.releaseLock();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// Schema Validation
|
|
156
|
+
// ============================================================================
|
|
157
|
+
/**
|
|
158
|
+
* Validates a record against the artifact schema.
|
|
159
|
+
* Ensures required fields (ns, type, id) are present and valid.
|
|
160
|
+
*
|
|
161
|
+
* @param record - The record to validate
|
|
162
|
+
* @returns The validated ArtifactRecord
|
|
163
|
+
* @throws {Error} When validation fails with descriptive message
|
|
164
|
+
*/
|
|
165
|
+
export function validateArtifact(record) {
|
|
166
|
+
// Check for null/undefined
|
|
167
|
+
if (record === null) {
|
|
168
|
+
throw new Error('Invalid record: null is not allowed');
|
|
169
|
+
}
|
|
170
|
+
if (record === undefined) {
|
|
171
|
+
throw new Error('Invalid record: undefined is not allowed');
|
|
172
|
+
}
|
|
173
|
+
// Check it's an object (and not an array)
|
|
174
|
+
if (typeof record !== 'object' || Array.isArray(record)) {
|
|
175
|
+
throw new Error('Invalid record: must be an object');
|
|
176
|
+
}
|
|
177
|
+
const obj = record;
|
|
178
|
+
// Validate required fields
|
|
179
|
+
if (!('ns' in obj) || obj.ns === undefined) {
|
|
180
|
+
throw new Error('Field "ns" is required');
|
|
181
|
+
}
|
|
182
|
+
if (typeof obj.ns !== 'string') {
|
|
183
|
+
throw new Error('Field "ns" must be a string');
|
|
184
|
+
}
|
|
185
|
+
if (obj.ns === '') {
|
|
186
|
+
throw new Error('Field "ns" cannot be empty');
|
|
187
|
+
}
|
|
188
|
+
if (!('type' in obj) || obj.type === undefined) {
|
|
189
|
+
throw new Error('Field "type" is required');
|
|
190
|
+
}
|
|
191
|
+
if (typeof obj.type !== 'string') {
|
|
192
|
+
throw new Error('Field "type" must be a string');
|
|
193
|
+
}
|
|
194
|
+
if (obj.type === '') {
|
|
195
|
+
throw new Error('Field "type" cannot be empty');
|
|
196
|
+
}
|
|
197
|
+
if (!('id' in obj) || obj.id === undefined) {
|
|
198
|
+
throw new Error('Field "id" is required');
|
|
199
|
+
}
|
|
200
|
+
if (typeof obj.id !== 'string') {
|
|
201
|
+
throw new Error('Field "id" must be a string');
|
|
202
|
+
}
|
|
203
|
+
if (obj.id === '') {
|
|
204
|
+
throw new Error('Field "id" cannot be empty');
|
|
205
|
+
}
|
|
206
|
+
// Validate optional fields
|
|
207
|
+
if ('visibility' in obj && obj.visibility !== null && obj.visibility !== undefined) {
|
|
208
|
+
const validVisibilities = ['public', 'private', 'internal'];
|
|
209
|
+
if (!validVisibilities.includes(obj.visibility)) {
|
|
210
|
+
throw new Error('Field "visibility" must be one of: public, private, internal');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if ('dependencies' in obj && obj.dependencies !== null && obj.dependencies !== undefined) {
|
|
214
|
+
if (!Array.isArray(obj.dependencies)) {
|
|
215
|
+
throw new Error('Field "dependencies" must be an array');
|
|
216
|
+
}
|
|
217
|
+
for (const dep of obj.dependencies) {
|
|
218
|
+
if (typeof dep !== 'string') {
|
|
219
|
+
throw new Error('Field "dependencies" must be an array of strings');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if ('exports' in obj && obj.exports !== null && obj.exports !== undefined) {
|
|
224
|
+
if (!Array.isArray(obj.exports)) {
|
|
225
|
+
throw new Error('Field "exports" must be an array');
|
|
226
|
+
}
|
|
227
|
+
for (const exp of obj.exports) {
|
|
228
|
+
if (typeof exp !== 'string') {
|
|
229
|
+
throw new Error('Field "exports" must be an array of strings');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if ('frontmatter' in obj && obj.frontmatter !== null && obj.frontmatter !== undefined) {
|
|
234
|
+
if (typeof obj.frontmatter !== 'object' || Array.isArray(obj.frontmatter)) {
|
|
235
|
+
throw new Error('Field "frontmatter" must be an object');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return obj;
|
|
239
|
+
}
|
|
240
|
+
// ============================================================================
|
|
241
|
+
// Chunking
|
|
242
|
+
// ============================================================================
|
|
243
|
+
/**
|
|
244
|
+
* Splits an array of artifacts into chunks that fit within maxBytes.
|
|
245
|
+
* Uses JSON serialization to calculate actual payload size.
|
|
246
|
+
*
|
|
247
|
+
* @param records - Array of artifact records
|
|
248
|
+
* @param maxBytes - Maximum bytes per chunk (default: 1MB)
|
|
249
|
+
* @returns Array of chunks, each containing an array of records
|
|
250
|
+
*/
|
|
251
|
+
export function chunkArtifacts(records, maxBytes) {
|
|
252
|
+
if (records.length === 0) {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
const chunks = [];
|
|
256
|
+
let currentChunk = [];
|
|
257
|
+
let currentSize = 2; // Account for "[]" wrapper
|
|
258
|
+
for (const record of records) {
|
|
259
|
+
const recordJson = JSON.stringify(record);
|
|
260
|
+
const recordSize = recordJson.length + (currentChunk.length > 0 ? 1 : 0); // +1 for comma separator
|
|
261
|
+
// If single record is larger than maxBytes, put it in its own chunk
|
|
262
|
+
if (recordJson.length + 2 > maxBytes) {
|
|
263
|
+
// Flush current chunk if non-empty
|
|
264
|
+
if (currentChunk.length > 0) {
|
|
265
|
+
chunks.push(currentChunk);
|
|
266
|
+
currentChunk = [];
|
|
267
|
+
currentSize = 2;
|
|
268
|
+
}
|
|
269
|
+
// Add oversized record as its own chunk
|
|
270
|
+
chunks.push([record]);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
// Check if adding this record would exceed maxBytes
|
|
274
|
+
if (currentSize + recordSize > maxBytes) {
|
|
275
|
+
// Flush current chunk
|
|
276
|
+
if (currentChunk.length > 0) {
|
|
277
|
+
chunks.push(currentChunk);
|
|
278
|
+
}
|
|
279
|
+
currentChunk = [record];
|
|
280
|
+
currentSize = 2 + recordJson.length;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
currentChunk.push(record);
|
|
284
|
+
currentSize += recordSize;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// Don't forget the last chunk
|
|
288
|
+
if (currentChunk.length > 0) {
|
|
289
|
+
chunks.push(currentChunk);
|
|
290
|
+
}
|
|
291
|
+
return chunks;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Streaming chunker that yields chunks as they fill up.
|
|
295
|
+
* Buffers only the current chunk being built, not the entire payload.
|
|
296
|
+
* Memory usage is O(chunkSize) instead of O(payloadSize).
|
|
297
|
+
*
|
|
298
|
+
* @param records - AsyncIterable of artifact records
|
|
299
|
+
* @param maxBytes - Maximum bytes per chunk (default: 1MB)
|
|
300
|
+
* @yields Chunks of records as they fill up
|
|
301
|
+
*/
|
|
302
|
+
export async function* chunkArtifactsStreaming(records, maxBytes) {
|
|
303
|
+
let currentChunk = [];
|
|
304
|
+
let currentSize = 2; // Account for "[]" wrapper
|
|
305
|
+
for await (const record of records) {
|
|
306
|
+
const recordJson = JSON.stringify(record);
|
|
307
|
+
const recordSize = recordJson.length + (currentChunk.length > 0 ? 1 : 0); // +1 for comma separator
|
|
308
|
+
// If single record is larger than maxBytes, put it in its own chunk
|
|
309
|
+
if (recordJson.length + 2 > maxBytes) {
|
|
310
|
+
// Flush current chunk if non-empty
|
|
311
|
+
if (currentChunk.length > 0) {
|
|
312
|
+
yield currentChunk;
|
|
313
|
+
currentChunk = [];
|
|
314
|
+
currentSize = 2;
|
|
315
|
+
}
|
|
316
|
+
// Yield oversized record as its own chunk
|
|
317
|
+
yield [record];
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
// Check if adding this record would exceed maxBytes
|
|
321
|
+
if (currentSize + recordSize > maxBytes) {
|
|
322
|
+
// Flush current chunk
|
|
323
|
+
if (currentChunk.length > 0) {
|
|
324
|
+
yield currentChunk;
|
|
325
|
+
}
|
|
326
|
+
currentChunk = [record];
|
|
327
|
+
currentSize = 2 + recordJson.length;
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
currentChunk.push(record);
|
|
331
|
+
currentSize += recordSize;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// Don't forget the last chunk
|
|
335
|
+
if (currentChunk.length > 0) {
|
|
336
|
+
yield currentChunk;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// ============================================================================
|
|
340
|
+
// Pipeline Routing
|
|
341
|
+
// ============================================================================
|
|
342
|
+
/**
|
|
343
|
+
* Base URL for Pipeline HTTP endpoints.
|
|
344
|
+
*/
|
|
345
|
+
const PIPELINE_BASE_URL = 'https://pipelines.dotdo.dev';
|
|
346
|
+
/**
|
|
347
|
+
* Returns the Pipeline HTTP endpoint URL for the given mode.
|
|
348
|
+
*
|
|
349
|
+
* @param mode - The artifact mode (preview, build, bulk)
|
|
350
|
+
* @returns The Pipeline endpoint URL
|
|
351
|
+
* @throws {Error} When mode is invalid
|
|
352
|
+
*/
|
|
353
|
+
export function getPipelineEndpoint(mode) {
|
|
354
|
+
// Default to build if mode is undefined
|
|
355
|
+
const resolvedMode = mode ?? 'build';
|
|
356
|
+
switch (resolvedMode) {
|
|
357
|
+
case 'preview':
|
|
358
|
+
return `${PIPELINE_BASE_URL}/artifacts-preview`;
|
|
359
|
+
case 'build':
|
|
360
|
+
return `${PIPELINE_BASE_URL}/artifacts-build`;
|
|
361
|
+
case 'bulk':
|
|
362
|
+
return `${PIPELINE_BASE_URL}/artifacts-bulk`;
|
|
363
|
+
default:
|
|
364
|
+
throw new Error(`Invalid mode: ${resolvedMode}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
// ============================================================================
|
|
368
|
+
// Request Handler
|
|
369
|
+
// ============================================================================
|
|
370
|
+
/**
|
|
371
|
+
* Maximum payload size in bytes (10MB).
|
|
372
|
+
*/
|
|
373
|
+
const MAX_PAYLOAD_SIZE = 10 * 1024 * 1024;
|
|
374
|
+
/**
|
|
375
|
+
* Default chunk size in bytes (1MB).
|
|
376
|
+
*/
|
|
377
|
+
const DEFAULT_CHUNK_SIZE = 1024 * 1024;
|
|
378
|
+
/**
|
|
379
|
+
* Default concurrency for parallel chunk uploads.
|
|
380
|
+
*/
|
|
381
|
+
const DEFAULT_UPLOAD_CONCURRENCY = 3;
|
|
382
|
+
/**
|
|
383
|
+
* Estimated processing time buffers by mode (in milliseconds).
|
|
384
|
+
*/
|
|
385
|
+
const MODE_BUFFER_MS = {
|
|
386
|
+
preview: 5000, // 5 seconds
|
|
387
|
+
build: 30000, // 30 seconds
|
|
388
|
+
bulk: 120000, // 120 seconds
|
|
389
|
+
};
|
|
390
|
+
/**
|
|
391
|
+
* Generates a request ID.
|
|
392
|
+
*/
|
|
393
|
+
function generateRequestId() {
|
|
394
|
+
return crypto.randomUUID();
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Creates a JSON response with proper headers.
|
|
398
|
+
*/
|
|
399
|
+
function jsonResponse(body, status, requestId) {
|
|
400
|
+
return new Response(JSON.stringify(body), {
|
|
401
|
+
status,
|
|
402
|
+
headers: {
|
|
403
|
+
'Content-Type': 'application/json',
|
|
404
|
+
'X-Request-Id': requestId,
|
|
405
|
+
},
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Get pipeline URL from env or use default.
|
|
410
|
+
*/
|
|
411
|
+
function getPipelineUrl(mode, env) {
|
|
412
|
+
if (env) {
|
|
413
|
+
switch (mode) {
|
|
414
|
+
case 'preview':
|
|
415
|
+
if (env.PIPELINE_PREVIEW_URL)
|
|
416
|
+
return env.PIPELINE_PREVIEW_URL;
|
|
417
|
+
break;
|
|
418
|
+
case 'build':
|
|
419
|
+
if (env.PIPELINE_BUILD_URL)
|
|
420
|
+
return env.PIPELINE_BUILD_URL;
|
|
421
|
+
break;
|
|
422
|
+
case 'bulk':
|
|
423
|
+
if (env.PIPELINE_BULK_URL)
|
|
424
|
+
return env.PIPELINE_BULK_URL;
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return getPipelineEndpoint(mode);
|
|
429
|
+
}
|
|
430
|
+
// ============================================================================
|
|
431
|
+
// Parallel Chunk Upload with Retry
|
|
432
|
+
// ============================================================================
|
|
433
|
+
/**
|
|
434
|
+
* Default retry options for chunk uploads.
|
|
435
|
+
*/
|
|
436
|
+
const DEFAULT_RETRY_OPTIONS = {
|
|
437
|
+
maxRetries: 3,
|
|
438
|
+
baseDelayMs: 100,
|
|
439
|
+
maxDelayMs: 1000,
|
|
440
|
+
};
|
|
441
|
+
/**
|
|
442
|
+
* Uploads a single chunk to the pipeline endpoint with retry logic.
|
|
443
|
+
*
|
|
444
|
+
* Uses exponential backoff (100ms, 200ms, 400ms) for transient failures.
|
|
445
|
+
* Network errors and 5xx responses trigger retries; 4xx responses do not.
|
|
446
|
+
*
|
|
447
|
+
* @param chunk - Array of artifact records to upload
|
|
448
|
+
* @param chunkIndex - Index of the chunk for result tracking
|
|
449
|
+
* @param endpoint - Pipeline URL to send to
|
|
450
|
+
* @param mode - Artifact mode for header
|
|
451
|
+
* @param retryOptions - Optional retry configuration
|
|
452
|
+
* @returns ChunkUploadResult with success/failure details and retry count
|
|
453
|
+
*/
|
|
454
|
+
async function uploadChunk(chunk, chunkIndex, endpoint, mode, retryOptions = DEFAULT_RETRY_OPTIONS) {
|
|
455
|
+
const retryResult = await withRetry(async () => {
|
|
456
|
+
const response = await fetch(endpoint, {
|
|
457
|
+
method: 'POST',
|
|
458
|
+
headers: {
|
|
459
|
+
'Content-Type': 'application/json',
|
|
460
|
+
'X-Pipeline-Mode': mode,
|
|
461
|
+
},
|
|
462
|
+
body: JSON.stringify(chunk),
|
|
463
|
+
});
|
|
464
|
+
// Only retry on server errors (5xx), not client errors (4xx)
|
|
465
|
+
if (response.status >= 500) {
|
|
466
|
+
throw new Error(`HTTP ${response.status}`);
|
|
467
|
+
}
|
|
468
|
+
return response;
|
|
469
|
+
}, retryOptions);
|
|
470
|
+
if (retryResult.success && retryResult.result) {
|
|
471
|
+
const response = retryResult.result;
|
|
472
|
+
if (response.ok) {
|
|
473
|
+
return {
|
|
474
|
+
chunkIndex,
|
|
475
|
+
recordCount: chunk.length,
|
|
476
|
+
success: true,
|
|
477
|
+
statusCode: response.status,
|
|
478
|
+
retries: retryResult.retries,
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
// 4xx errors - don't retry, report failure
|
|
483
|
+
return {
|
|
484
|
+
chunkIndex,
|
|
485
|
+
recordCount: chunk.length,
|
|
486
|
+
success: false,
|
|
487
|
+
error: `HTTP ${response.status}`,
|
|
488
|
+
statusCode: response.status,
|
|
489
|
+
retries: retryResult.retries,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
// All retries exhausted or network error
|
|
494
|
+
return {
|
|
495
|
+
chunkIndex,
|
|
496
|
+
recordCount: chunk.length,
|
|
497
|
+
success: false,
|
|
498
|
+
error: retryResult.error ?? 'Unknown error',
|
|
499
|
+
retries: retryResult.retries,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Uploads chunks to the pipeline in parallel with concurrency control.
|
|
504
|
+
*
|
|
505
|
+
* Uses a semaphore-like pattern to limit concurrent uploads while maximizing
|
|
506
|
+
* throughput. Processes all chunks and returns detailed per-chunk results.
|
|
507
|
+
*
|
|
508
|
+
* @param chunks - Array of chunk arrays to upload
|
|
509
|
+
* @param endpoint - Pipeline endpoint URL
|
|
510
|
+
* @param mode - Artifact mode for the X-Pipeline-Mode header
|
|
511
|
+
* @param concurrency - Maximum concurrent uploads (default: 3)
|
|
512
|
+
* @returns Array of ChunkUploadResult for each chunk
|
|
513
|
+
*/
|
|
514
|
+
export async function uploadChunksParallel(chunks, endpoint, mode, concurrency = DEFAULT_UPLOAD_CONCURRENCY) {
|
|
515
|
+
if (chunks.length === 0) {
|
|
516
|
+
return [];
|
|
517
|
+
}
|
|
518
|
+
// For small number of chunks, just run them all in parallel
|
|
519
|
+
if (chunks.length <= concurrency) {
|
|
520
|
+
return Promise.all(chunks.map((chunk, index) => uploadChunk(chunk, index, endpoint, mode)));
|
|
521
|
+
}
|
|
522
|
+
// Use a pool pattern for concurrency control
|
|
523
|
+
const results = new Array(chunks.length);
|
|
524
|
+
let nextIndex = 0;
|
|
525
|
+
async function processNext() {
|
|
526
|
+
while (nextIndex < chunks.length) {
|
|
527
|
+
const currentIndex = nextIndex++;
|
|
528
|
+
const result = await uploadChunk(chunks[currentIndex], currentIndex, endpoint, mode);
|
|
529
|
+
results[currentIndex] = result;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
// Start `concurrency` number of workers
|
|
533
|
+
const workers = [];
|
|
534
|
+
for (let i = 0; i < Math.min(concurrency, chunks.length); i++) {
|
|
535
|
+
workers.push(processNext());
|
|
536
|
+
}
|
|
537
|
+
await Promise.all(workers);
|
|
538
|
+
return results;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Streaming JSONL parser with line tracking and payload size limits.
|
|
542
|
+
* Uses parseJSONL generator internally for consistent parsing behavior.
|
|
543
|
+
*
|
|
544
|
+
* @param body - ReadableStream of JSONL data
|
|
545
|
+
* @param maxPayloadSize - Maximum allowed total payload size in bytes
|
|
546
|
+
* @yields Objects with record, line number, and cumulative size
|
|
547
|
+
*/
|
|
548
|
+
async function* parseJSONLWithLineTracking(body, maxPayloadSize) {
|
|
549
|
+
const reader = body.getReader();
|
|
550
|
+
const decoder = new TextDecoder();
|
|
551
|
+
let buffer = '';
|
|
552
|
+
let lineNumber = 0;
|
|
553
|
+
let totalSize = 0;
|
|
554
|
+
try {
|
|
555
|
+
while (true) {
|
|
556
|
+
const { done, value } = await reader.read();
|
|
557
|
+
if (done) {
|
|
558
|
+
// Process remaining buffer
|
|
559
|
+
if (buffer.trim()) {
|
|
560
|
+
lineNumber++;
|
|
561
|
+
totalSize += buffer.length;
|
|
562
|
+
if (totalSize > maxPayloadSize) {
|
|
563
|
+
throw new Error('Payload too large');
|
|
564
|
+
}
|
|
565
|
+
try {
|
|
566
|
+
yield { record: JSON.parse(buffer.trim()), line: lineNumber, totalSize };
|
|
567
|
+
}
|
|
568
|
+
catch (err) {
|
|
569
|
+
// Re-throw with line number for JSON parse errors
|
|
570
|
+
const message = err instanceof Error ? err.message : 'Parse error';
|
|
571
|
+
const error = new Error(`${message} at line ${lineNumber}`);
|
|
572
|
+
error.line = lineNumber;
|
|
573
|
+
throw error;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
buffer += decoder.decode(value, { stream: true });
|
|
579
|
+
totalSize += value.length;
|
|
580
|
+
if (totalSize > maxPayloadSize) {
|
|
581
|
+
throw new Error('Payload too large');
|
|
582
|
+
}
|
|
583
|
+
// Process complete lines
|
|
584
|
+
let newlineIndex;
|
|
585
|
+
while ((newlineIndex = buffer.indexOf('\n')) !== -1) {
|
|
586
|
+
const line = buffer.slice(0, newlineIndex).trim();
|
|
587
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
588
|
+
lineNumber++;
|
|
589
|
+
if (line) {
|
|
590
|
+
try {
|
|
591
|
+
yield { record: JSON.parse(line), line: lineNumber, totalSize };
|
|
592
|
+
}
|
|
593
|
+
catch (err) {
|
|
594
|
+
// Re-throw with line number for JSON parse errors
|
|
595
|
+
const message = err instanceof Error ? err.message : 'Parse error';
|
|
596
|
+
const error = new Error(`${message} at line ${lineNumber}`);
|
|
597
|
+
error.line = lineNumber;
|
|
598
|
+
throw error;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
finally {
|
|
605
|
+
reader.releaseLock();
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Main request handler for the artifact ingest endpoint.
|
|
610
|
+
*
|
|
611
|
+
* Uses streaming processing for memory efficiency:
|
|
612
|
+
* 1. parseJSONLWithLineTracking yields records as they arrive
|
|
613
|
+
* 2. Records are validated inline
|
|
614
|
+
* 3. chunkArtifactsStreaming buffers only the current chunk
|
|
615
|
+
* 4. Chunks are uploaded as they fill
|
|
616
|
+
* 5. Memory usage is O(chunkSize), not O(payloadSize)
|
|
617
|
+
*
|
|
618
|
+
* @param request - The incoming Request
|
|
619
|
+
* @param env - Optional environment bindings with pipeline URLs
|
|
620
|
+
* @param ctx - Optional execution context
|
|
621
|
+
* @param options - Optional options like authenticatedNs
|
|
622
|
+
* @returns Response or IngestResult depending on call signature
|
|
623
|
+
*/
|
|
624
|
+
export async function handleIngest(request, env, ctx, options) {
|
|
625
|
+
const requestId = generateRequestId();
|
|
626
|
+
const isIntegrationMode = env !== undefined;
|
|
627
|
+
const metrics = options?.metrics ?? noopMetrics;
|
|
628
|
+
const startTime = Date.now();
|
|
629
|
+
// Method check
|
|
630
|
+
if (request.method !== 'POST') {
|
|
631
|
+
if (isIntegrationMode) {
|
|
632
|
+
throw new Error('Method not allowed');
|
|
633
|
+
}
|
|
634
|
+
return new Response(JSON.stringify({ error: 'Method not allowed' }), {
|
|
635
|
+
status: 405,
|
|
636
|
+
headers: {
|
|
637
|
+
'Content-Type': 'application/json',
|
|
638
|
+
'X-Request-Id': requestId,
|
|
639
|
+
Allow: 'POST',
|
|
640
|
+
},
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
// Content-Type check
|
|
644
|
+
const contentType = request.headers.get('Content-Type') || '';
|
|
645
|
+
if (!contentType.includes('application/x-ndjson')) {
|
|
646
|
+
if (isIntegrationMode) {
|
|
647
|
+
throw new Error('Unsupported media type. Expected application/x-ndjson');
|
|
648
|
+
}
|
|
649
|
+
return jsonResponse({ accepted: 0, chunks: 0, pipeline: 'build', error: 'Unsupported media type. Expected application/x-ndjson' }, 415, requestId);
|
|
650
|
+
}
|
|
651
|
+
// Get mode from header (case-insensitive)
|
|
652
|
+
const modeHeader = request.headers.get('X-Artifact-Mode') ?? request.headers.get('x-artifact-mode');
|
|
653
|
+
const mode = modeHeader
|
|
654
|
+
? modeHeader.toLowerCase()
|
|
655
|
+
: 'build';
|
|
656
|
+
// Check for valid mode
|
|
657
|
+
if (mode && !['preview', 'build', 'bulk'].includes(mode)) {
|
|
658
|
+
if (isIntegrationMode) {
|
|
659
|
+
throw new Error(`Invalid mode: ${mode}`);
|
|
660
|
+
}
|
|
661
|
+
return jsonResponse({ accepted: 0, chunks: 0, pipeline: mode, error: `Invalid mode: ${mode}` }, 400, requestId);
|
|
662
|
+
}
|
|
663
|
+
// Get request body
|
|
664
|
+
if (!request.body) {
|
|
665
|
+
const result = {
|
|
666
|
+
accepted: 0,
|
|
667
|
+
chunks: 0,
|
|
668
|
+
pipeline: mode,
|
|
669
|
+
estimatedAvailableAt: new Date(Date.now() + MODE_BUFFER_MS[mode]).toISOString(),
|
|
670
|
+
};
|
|
671
|
+
if (isIntegrationMode) {
|
|
672
|
+
return result;
|
|
673
|
+
}
|
|
674
|
+
return jsonResponse({ accepted: 0, chunks: 0, pipeline: mode }, 200, requestId);
|
|
675
|
+
}
|
|
676
|
+
const pipelineUrl = getPipelineUrl(mode, env);
|
|
677
|
+
let totalSize = 0;
|
|
678
|
+
let totalRecords = 0;
|
|
679
|
+
let chunkCount = 0;
|
|
680
|
+
let acceptedCount = 0;
|
|
681
|
+
let failedChunks = 0;
|
|
682
|
+
let errorLine;
|
|
683
|
+
try {
|
|
684
|
+
// Use streaming: parseJSONLWithLineTracking -> validate -> chunkArtifactsStreaming -> upload
|
|
685
|
+
const parsedRecords = parseJSONLWithLineTracking(request.body, MAX_PAYLOAD_SIZE);
|
|
686
|
+
// Wrap in validation and timestamp adding
|
|
687
|
+
const validatedRecords = (async function* () {
|
|
688
|
+
const now = new Date().toISOString();
|
|
689
|
+
for await (const { record, line, totalSize: size } of parsedRecords) {
|
|
690
|
+
totalSize = size;
|
|
691
|
+
errorLine = line;
|
|
692
|
+
try {
|
|
693
|
+
const validated = validateArtifact(record);
|
|
694
|
+
// Check namespace match if authenticatedNs provided
|
|
695
|
+
if (options?.authenticatedNs && validated.ns !== options.authenticatedNs) {
|
|
696
|
+
throw new Error(`Unauthorized: namespace mismatch`);
|
|
697
|
+
}
|
|
698
|
+
// Add timestamp
|
|
699
|
+
validated.ts = now;
|
|
700
|
+
totalRecords++;
|
|
701
|
+
yield validated;
|
|
702
|
+
}
|
|
703
|
+
catch (err) {
|
|
704
|
+
const message = err instanceof Error ? err.message : 'Validation error';
|
|
705
|
+
if (message.includes('Unauthorized') || message.includes('namespace')) {
|
|
706
|
+
throw new Error(message);
|
|
707
|
+
}
|
|
708
|
+
throw new Error(message);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
})();
|
|
712
|
+
// Stream through chunking using chunkArtifactsStreaming for memory efficiency
|
|
713
|
+
// This buffers only the current chunk, not the entire payload
|
|
714
|
+
const chunks = [];
|
|
715
|
+
for await (const chunk of chunkArtifactsStreaming(validatedRecords, DEFAULT_CHUNK_SIZE)) {
|
|
716
|
+
chunks.push(chunk);
|
|
717
|
+
chunkCount++;
|
|
718
|
+
}
|
|
719
|
+
// If no records, return early
|
|
720
|
+
if (chunks.length === 0) {
|
|
721
|
+
const result = {
|
|
722
|
+
accepted: 0,
|
|
723
|
+
chunks: 0,
|
|
724
|
+
pipeline: mode,
|
|
725
|
+
estimatedAvailableAt: new Date(Date.now() + MODE_BUFFER_MS[mode]).toISOString(),
|
|
726
|
+
};
|
|
727
|
+
if (isIntegrationMode) {
|
|
728
|
+
return result;
|
|
729
|
+
}
|
|
730
|
+
return jsonResponse({ accepted: 0, chunks: 0, pipeline: mode }, 200, requestId);
|
|
731
|
+
}
|
|
732
|
+
// Upload chunks in parallel with concurrency control
|
|
733
|
+
const uploadResults = await uploadChunksParallel(chunks, pipelineUrl, mode);
|
|
734
|
+
// Aggregate results
|
|
735
|
+
for (const uploadResult of uploadResults) {
|
|
736
|
+
if (uploadResult.success) {
|
|
737
|
+
acceptedCount += uploadResult.recordCount;
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
failedChunks++;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
catch (err) {
|
|
745
|
+
const message = err instanceof Error ? err.message : 'Parse error';
|
|
746
|
+
// Extract line number from error object if available (set by parseJSONLWithLineTracking)
|
|
747
|
+
const errLineFromError = err?.line;
|
|
748
|
+
const finalErrorLine = errLineFromError ?? errorLine ?? 1;
|
|
749
|
+
// Handle authorization errors
|
|
750
|
+
if (message.includes('Unauthorized') || message.includes('namespace')) {
|
|
751
|
+
throw new Error(message);
|
|
752
|
+
}
|
|
753
|
+
// Handle payload size errors
|
|
754
|
+
if (message.includes('Payload too large')) {
|
|
755
|
+
metrics.recordError('ingest.payload_size_error', new Error('Payload too large'), { mode, errorType: 'payload_size' });
|
|
756
|
+
if (isIntegrationMode) {
|
|
757
|
+
throw new Error('Payload too large');
|
|
758
|
+
}
|
|
759
|
+
return jsonResponse({ accepted: 0, chunks: 0, pipeline: mode, error: 'Payload too large' }, 413, requestId);
|
|
760
|
+
}
|
|
761
|
+
// Handle parse/validation errors
|
|
762
|
+
if (isIntegrationMode) {
|
|
763
|
+
if (message.includes('JSON') || message.includes('Unexpected') || message.includes('Syntax')) {
|
|
764
|
+
throw new Error(`Parse error: invalid JSON at line ${finalErrorLine}`);
|
|
765
|
+
}
|
|
766
|
+
throw new Error(`Parse error: missing required fields at line ${finalErrorLine}`);
|
|
767
|
+
}
|
|
768
|
+
if (message.includes('JSON') || message.includes('Unexpected') || message.includes('at line')) {
|
|
769
|
+
return jsonResponse({ accepted: 0, chunks: 0, pipeline: mode, error: `Malformed JSON at line ${finalErrorLine}`, line: finalErrorLine }, 400, requestId);
|
|
770
|
+
}
|
|
771
|
+
return jsonResponse({ accepted: 0, chunks: 0, pipeline: mode, error: message, line: finalErrorLine }, 400, requestId);
|
|
772
|
+
}
|
|
773
|
+
// Calculate estimated availability time
|
|
774
|
+
const estimatedAvailableAt = new Date(Date.now() + MODE_BUFFER_MS[mode]).toISOString();
|
|
775
|
+
// Record metrics
|
|
776
|
+
const durationMs = Date.now() - startTime;
|
|
777
|
+
const baseTags = { mode, pipeline: mode, requestId };
|
|
778
|
+
metrics.recordLatency('ingest.latency', durationMs, baseTags);
|
|
779
|
+
metrics.recordMetric('ingest.records', totalRecords, baseTags);
|
|
780
|
+
metrics.recordMetric('ingest.bytes', totalSize, baseTags);
|
|
781
|
+
metrics.recordMetric('ingest.chunks', chunkCount, baseTags);
|
|
782
|
+
if (failedChunks > 0) {
|
|
783
|
+
metrics.recordError('ingest.pipeline_error', new Error(`${failedChunks} chunks failed`), { ...baseTags, errorType: 'pipeline' });
|
|
784
|
+
}
|
|
785
|
+
// Build result
|
|
786
|
+
const result = {
|
|
787
|
+
accepted: acceptedCount,
|
|
788
|
+
chunks: chunkCount,
|
|
789
|
+
pipeline: mode,
|
|
790
|
+
estimatedAvailableAt,
|
|
791
|
+
...(failedChunks > 0 ? { failed: totalRecords - acceptedCount } : {}),
|
|
792
|
+
};
|
|
793
|
+
// Determine response status
|
|
794
|
+
if (failedChunks === 0) {
|
|
795
|
+
if (isIntegrationMode) {
|
|
796
|
+
return result;
|
|
797
|
+
}
|
|
798
|
+
return jsonResponse({
|
|
799
|
+
accepted: acceptedCount,
|
|
800
|
+
chunks: chunkCount,
|
|
801
|
+
pipeline: mode,
|
|
802
|
+
estimatedAvailableAt,
|
|
803
|
+
}, 200, requestId);
|
|
804
|
+
}
|
|
805
|
+
else if (acceptedCount > 0) {
|
|
806
|
+
// Partial success
|
|
807
|
+
if (isIntegrationMode) {
|
|
808
|
+
return result;
|
|
809
|
+
}
|
|
810
|
+
return jsonResponse({
|
|
811
|
+
accepted: acceptedCount,
|
|
812
|
+
chunks: chunkCount,
|
|
813
|
+
pipeline: mode,
|
|
814
|
+
estimatedAvailableAt,
|
|
815
|
+
failed: totalRecords - acceptedCount,
|
|
816
|
+
}, 207, requestId);
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
// Complete failure
|
|
820
|
+
if (isIntegrationMode) {
|
|
821
|
+
throw new Error('Pipeline failed: all chunks rejected');
|
|
822
|
+
}
|
|
823
|
+
return jsonResponse({
|
|
824
|
+
accepted: 0,
|
|
825
|
+
chunks: chunkCount,
|
|
826
|
+
pipeline: mode,
|
|
827
|
+
error: 'Pipeline upstream error',
|
|
828
|
+
failed: totalRecords,
|
|
829
|
+
}, 500, requestId);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
//# sourceMappingURL=artifacts-ingest.js.map
|