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,1174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IntegrationsDO - Provider Registry Durable Object
|
|
3
|
+
*
|
|
4
|
+
* Manages integration providers (GitHub, Stripe, Google, etc.) with:
|
|
5
|
+
* - OAuth configuration
|
|
6
|
+
* - Webhook verification
|
|
7
|
+
* - Rate limiting
|
|
8
|
+
* - Action definitions
|
|
9
|
+
*/
|
|
10
|
+
export class SDKError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
requestId;
|
|
13
|
+
statusCode;
|
|
14
|
+
retryable;
|
|
15
|
+
constructor(message, code, requestId, statusCode, retryable = false) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'SDKError';
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.requestId = requestId;
|
|
20
|
+
this.statusCode = statusCode;
|
|
21
|
+
this.retryable = retryable;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// BUILT-IN PROVIDERS
|
|
26
|
+
// ============================================================================
|
|
27
|
+
const BUILT_IN_PROVIDERS = [
|
|
28
|
+
{
|
|
29
|
+
id: 'github',
|
|
30
|
+
slug: 'github',
|
|
31
|
+
name: 'GitHub',
|
|
32
|
+
accountType: 'devtools',
|
|
33
|
+
icon: 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png',
|
|
34
|
+
oauthConfig: {
|
|
35
|
+
authUrl: 'https://github.com/login/oauth/authorize',
|
|
36
|
+
tokenUrl: 'https://github.com/login/oauth/access_token',
|
|
37
|
+
scopes: ['repo', 'user', 'read:org'],
|
|
38
|
+
clientIdEnvVar: 'GITHUB_CLIENT_ID',
|
|
39
|
+
clientSecretEnvVar: 'GITHUB_CLIENT_SECRET',
|
|
40
|
+
},
|
|
41
|
+
webhookConfig: {
|
|
42
|
+
signatureHeader: 'X-Hub-Signature-256',
|
|
43
|
+
algorithm: 'sha256',
|
|
44
|
+
secretEnvVar: 'GITHUB_WEBHOOK_SECRET',
|
|
45
|
+
},
|
|
46
|
+
actions: [
|
|
47
|
+
{
|
|
48
|
+
name: 'listRepos',
|
|
49
|
+
description: 'List repositories for the authenticated user',
|
|
50
|
+
scopes: ['repo'],
|
|
51
|
+
method: 'GET',
|
|
52
|
+
path: '/user/repos',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'createIssue',
|
|
56
|
+
description: 'Create an issue in a repository',
|
|
57
|
+
scopes: ['repo'],
|
|
58
|
+
method: 'POST',
|
|
59
|
+
path: '/repos/{owner}/{repo}/issues',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
rateLimit: { max: 5000, windowMs: 3600000 },
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'stripe',
|
|
66
|
+
slug: 'stripe',
|
|
67
|
+
name: 'Stripe',
|
|
68
|
+
accountType: 'payments',
|
|
69
|
+
icon: 'https://stripe.com/img/v3/home/social.png',
|
|
70
|
+
oauthConfig: {
|
|
71
|
+
authUrl: 'https://connect.stripe.com/oauth/authorize',
|
|
72
|
+
tokenUrl: 'https://connect.stripe.com/oauth/token',
|
|
73
|
+
scopes: ['read_write'],
|
|
74
|
+
clientIdEnvVar: 'STRIPE_CLIENT_ID',
|
|
75
|
+
clientSecretEnvVar: 'STRIPE_CLIENT_SECRET',
|
|
76
|
+
},
|
|
77
|
+
webhookConfig: {
|
|
78
|
+
signatureHeader: 'Stripe-Signature',
|
|
79
|
+
algorithm: 'sha256',
|
|
80
|
+
secretEnvVar: 'STRIPE_WEBHOOK_SECRET',
|
|
81
|
+
},
|
|
82
|
+
actions: [
|
|
83
|
+
{
|
|
84
|
+
name: 'createPaymentIntent',
|
|
85
|
+
description: 'Create a payment intent',
|
|
86
|
+
scopes: ['read_write'],
|
|
87
|
+
method: 'POST',
|
|
88
|
+
path: '/v1/payment_intents',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'listCustomers',
|
|
92
|
+
description: 'List all customers',
|
|
93
|
+
scopes: ['read_write'],
|
|
94
|
+
method: 'GET',
|
|
95
|
+
path: '/v1/customers',
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
rateLimit: { max: 100, windowMs: 1000 },
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'google',
|
|
102
|
+
slug: 'google',
|
|
103
|
+
name: 'Google',
|
|
104
|
+
accountType: 'productivity',
|
|
105
|
+
icon: 'https://www.google.com/favicon.ico',
|
|
106
|
+
oauthConfig: {
|
|
107
|
+
authUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
|
|
108
|
+
tokenUrl: 'https://oauth2.googleapis.com/token',
|
|
109
|
+
scopes: ['openid', 'email', 'profile'],
|
|
110
|
+
clientIdEnvVar: 'GOOGLE_CLIENT_ID',
|
|
111
|
+
clientSecretEnvVar: 'GOOGLE_CLIENT_SECRET',
|
|
112
|
+
},
|
|
113
|
+
actions: [
|
|
114
|
+
{
|
|
115
|
+
name: 'getUserInfo',
|
|
116
|
+
description: 'Get authenticated user info',
|
|
117
|
+
scopes: ['openid', 'email', 'profile'],
|
|
118
|
+
method: 'GET',
|
|
119
|
+
path: '/oauth2/v2/userinfo',
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
const BUILT_IN_SLUGS = new Set(BUILT_IN_PROVIDERS.map((p) => p.slug));
|
|
125
|
+
// ============================================================================
|
|
126
|
+
// BUILT-IN ACCOUNT TYPES
|
|
127
|
+
// ============================================================================
|
|
128
|
+
const BUILT_IN_ACCOUNT_TYPES = [
|
|
129
|
+
{
|
|
130
|
+
id: 'devtools',
|
|
131
|
+
slug: 'devtools',
|
|
132
|
+
name: 'Developer Tools',
|
|
133
|
+
icon: 'code',
|
|
134
|
+
description: 'Tools for software development, version control, and CI/CD',
|
|
135
|
+
providers: [],
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: 'crm',
|
|
139
|
+
slug: 'crm',
|
|
140
|
+
name: 'Customer Relationship Management',
|
|
141
|
+
icon: 'users',
|
|
142
|
+
description: 'Customer relationship and sales management tools',
|
|
143
|
+
providers: [],
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: 'payments',
|
|
147
|
+
slug: 'payments',
|
|
148
|
+
name: 'Payments',
|
|
149
|
+
icon: 'credit-card',
|
|
150
|
+
description: 'Payment processing and financial services',
|
|
151
|
+
providers: [],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: 'communication',
|
|
155
|
+
slug: 'communication',
|
|
156
|
+
name: 'Communication',
|
|
157
|
+
icon: 'message-circle',
|
|
158
|
+
description: 'Messaging, email, and communication platforms',
|
|
159
|
+
providers: [],
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: 'productivity',
|
|
163
|
+
slug: 'productivity',
|
|
164
|
+
name: 'Productivity',
|
|
165
|
+
icon: 'briefcase',
|
|
166
|
+
description: 'Productivity and collaboration tools',
|
|
167
|
+
providers: [],
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: 'storage',
|
|
171
|
+
slug: 'storage',
|
|
172
|
+
name: 'Storage',
|
|
173
|
+
icon: 'hard-drive',
|
|
174
|
+
description: 'Cloud storage and file management services',
|
|
175
|
+
providers: [],
|
|
176
|
+
},
|
|
177
|
+
];
|
|
178
|
+
const BUILT_IN_ACCOUNT_TYPE_SLUGS = new Set(BUILT_IN_ACCOUNT_TYPES.map((t) => t.slug));
|
|
179
|
+
// ============================================================================
|
|
180
|
+
// INTEGRATIONS DO
|
|
181
|
+
// ============================================================================
|
|
182
|
+
/**
|
|
183
|
+
* IntegrationsDO - standalone implementation for provider registry
|
|
184
|
+
*
|
|
185
|
+
* This class doesn't extend DO directly to allow for testing in node environment.
|
|
186
|
+
* It uses the same patterns and will be compatible with Cloudflare Workers runtime.
|
|
187
|
+
*/
|
|
188
|
+
export class IntegrationsDO {
|
|
189
|
+
ns = 'https://integrations.do';
|
|
190
|
+
ctx;
|
|
191
|
+
env;
|
|
192
|
+
// Registered providers (custom providers + re-registered built-ins)
|
|
193
|
+
registeredProviders = new Map();
|
|
194
|
+
// Track deleted slugs (so we don't fall back to built-ins for deleted providers)
|
|
195
|
+
deletedSlugs = new Set();
|
|
196
|
+
// Registered account types (custom account types + re-registered built-ins)
|
|
197
|
+
registeredAccountTypes = new Map();
|
|
198
|
+
// Track deleted account type slugs (so we don't fall back to built-ins for deleted types)
|
|
199
|
+
deletedAccountTypeSlugs = new Set();
|
|
200
|
+
initialized = false;
|
|
201
|
+
// Providers with extended actions (SDK support)
|
|
202
|
+
providersWithActions = new Map();
|
|
203
|
+
constructor(ctx, env) {
|
|
204
|
+
this.ctx = ctx;
|
|
205
|
+
this.env = env;
|
|
206
|
+
}
|
|
207
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
208
|
+
// INITIALIZATION
|
|
209
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
210
|
+
async ensureInitialized() {
|
|
211
|
+
if (this.initialized)
|
|
212
|
+
return;
|
|
213
|
+
// Load custom providers from storage (not built-ins)
|
|
214
|
+
const storedProviders = await this.ctx.storage.list({ prefix: 'provider:' });
|
|
215
|
+
for (const [, provider] of storedProviders) {
|
|
216
|
+
this.registeredProviders.set(provider.slug, provider);
|
|
217
|
+
}
|
|
218
|
+
// Load custom account types from storage (not built-ins)
|
|
219
|
+
const storedAccountTypes = await this.ctx.storage.list({ prefix: 'accountType:' });
|
|
220
|
+
for (const [, accountType] of storedAccountTypes) {
|
|
221
|
+
this.registeredAccountTypes.set(accountType.slug, accountType);
|
|
222
|
+
}
|
|
223
|
+
this.initialized = true;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get a built-in provider by slug (returns a copy)
|
|
227
|
+
*/
|
|
228
|
+
getBuiltInProvider(slug) {
|
|
229
|
+
const builtIn = BUILT_IN_PROVIDERS.find((p) => p.slug === slug);
|
|
230
|
+
if (builtIn) {
|
|
231
|
+
return { ...builtIn, actions: [...builtIn.actions] };
|
|
232
|
+
}
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get a built-in account type by slug (returns a copy with dynamic providers list)
|
|
237
|
+
*/
|
|
238
|
+
getBuiltInAccountType(slug) {
|
|
239
|
+
const builtIn = BUILT_IN_ACCOUNT_TYPES.find((t) => t.slug === slug);
|
|
240
|
+
if (builtIn) {
|
|
241
|
+
// Dynamically populate providers list from registered providers
|
|
242
|
+
const providers = this.getProvidersForAccountType(slug);
|
|
243
|
+
return { ...builtIn, providers };
|
|
244
|
+
}
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Get provider slugs for a given account type
|
|
249
|
+
*/
|
|
250
|
+
getProvidersForAccountType(accountTypeSlug) {
|
|
251
|
+
const providers = [];
|
|
252
|
+
for (const provider of this.registeredProviders.values()) {
|
|
253
|
+
if (provider.accountType === accountTypeSlug) {
|
|
254
|
+
providers.push(provider.slug);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return providers;
|
|
258
|
+
}
|
|
259
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
260
|
+
// VALIDATION
|
|
261
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
262
|
+
validateProvider(provider) {
|
|
263
|
+
// Validate OAuth config
|
|
264
|
+
if (!provider.oauthConfig) {
|
|
265
|
+
throw new Error('Invalid provider: oauthConfig is required');
|
|
266
|
+
}
|
|
267
|
+
const { authUrl, tokenUrl, clientIdEnvVar, clientSecretEnvVar } = provider.oauthConfig;
|
|
268
|
+
if (!authUrl || authUrl.trim() === '') {
|
|
269
|
+
throw new Error('Invalid provider: authUrl is required');
|
|
270
|
+
}
|
|
271
|
+
if (!tokenUrl || tokenUrl.trim() === '') {
|
|
272
|
+
throw new Error('Invalid provider: tokenUrl is required');
|
|
273
|
+
}
|
|
274
|
+
if (!clientIdEnvVar || clientIdEnvVar.trim() === '') {
|
|
275
|
+
throw new Error('Invalid provider: clientIdEnvVar is required');
|
|
276
|
+
}
|
|
277
|
+
if (!clientSecretEnvVar || clientSecretEnvVar.trim() === '') {
|
|
278
|
+
throw new Error('Invalid provider: clientSecretEnvVar is required');
|
|
279
|
+
}
|
|
280
|
+
// Validate URLs
|
|
281
|
+
try {
|
|
282
|
+
new URL(authUrl);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
throw new Error('Invalid provider: authUrl is not a valid URL');
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
new URL(tokenUrl);
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
throw new Error('Invalid provider: tokenUrl is not a valid URL');
|
|
292
|
+
}
|
|
293
|
+
// Validate rate limit if present
|
|
294
|
+
if (provider.rateLimit) {
|
|
295
|
+
if (provider.rateLimit.max <= 0) {
|
|
296
|
+
throw new Error('Invalid provider: rateLimit.max must be positive');
|
|
297
|
+
}
|
|
298
|
+
if (provider.rateLimit.windowMs <= 0) {
|
|
299
|
+
throw new Error('Invalid provider: rateLimit.windowMs must be positive');
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
304
|
+
// PROVIDER CRUD
|
|
305
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
306
|
+
async registerProvider(provider) {
|
|
307
|
+
await this.ensureInitialized();
|
|
308
|
+
const slug = provider.slug;
|
|
309
|
+
const id = provider.id || slug;
|
|
310
|
+
// Check for duplicates in registered providers
|
|
311
|
+
if (this.registeredProviders.has(slug)) {
|
|
312
|
+
throw new Error(`Provider with slug '${slug}' already exists`);
|
|
313
|
+
}
|
|
314
|
+
// Validate
|
|
315
|
+
this.validateProvider(provider);
|
|
316
|
+
const newProvider = {
|
|
317
|
+
...provider,
|
|
318
|
+
id,
|
|
319
|
+
actions: provider.actions ? [...provider.actions] : [],
|
|
320
|
+
};
|
|
321
|
+
// Store in registered providers
|
|
322
|
+
this.registeredProviders.set(slug, newProvider);
|
|
323
|
+
// Remove from deleted set (in case it was previously deleted)
|
|
324
|
+
this.deletedSlugs.delete(slug);
|
|
325
|
+
// Persist to storage
|
|
326
|
+
await this.ctx.storage.put(`provider:${slug}`, newProvider);
|
|
327
|
+
return newProvider;
|
|
328
|
+
}
|
|
329
|
+
async getProvider(slug) {
|
|
330
|
+
await this.ensureInitialized();
|
|
331
|
+
// If this slug was explicitly deleted, return null
|
|
332
|
+
if (this.deletedSlugs.has(slug)) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
// First check registered providers
|
|
336
|
+
const registered = this.registeredProviders.get(slug);
|
|
337
|
+
if (registered) {
|
|
338
|
+
return registered;
|
|
339
|
+
}
|
|
340
|
+
// Fall back to built-in providers
|
|
341
|
+
return this.getBuiltInProvider(slug) || null;
|
|
342
|
+
}
|
|
343
|
+
async getProviderById(id) {
|
|
344
|
+
await this.ensureInitialized();
|
|
345
|
+
// Check registered providers first
|
|
346
|
+
for (const provider of this.registeredProviders.values()) {
|
|
347
|
+
if (provider.id === id) {
|
|
348
|
+
return provider;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Check built-in providers
|
|
352
|
+
const builtIn = BUILT_IN_PROVIDERS.find((p) => p.id === id);
|
|
353
|
+
if (builtIn) {
|
|
354
|
+
return { ...builtIn, actions: [...builtIn.actions] };
|
|
355
|
+
}
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
async updateProvider(slug, updates) {
|
|
359
|
+
await this.ensureInitialized();
|
|
360
|
+
// Get existing provider (from registered or built-in)
|
|
361
|
+
const existing = this.registeredProviders.get(slug) || this.getBuiltInProvider(slug);
|
|
362
|
+
if (!existing) {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
// Cannot update slug
|
|
366
|
+
if (updates.slug && updates.slug !== slug) {
|
|
367
|
+
throw new Error('Cannot update slug: slug is immutable');
|
|
368
|
+
}
|
|
369
|
+
// Merge updates
|
|
370
|
+
const updated = {
|
|
371
|
+
...existing,
|
|
372
|
+
...updates,
|
|
373
|
+
id: existing.id, // Preserve id
|
|
374
|
+
slug: existing.slug, // Preserve slug
|
|
375
|
+
};
|
|
376
|
+
// Validate the updated provider
|
|
377
|
+
this.validateProvider(updated);
|
|
378
|
+
// Store as registered (even for built-ins that get updated)
|
|
379
|
+
this.registeredProviders.set(slug, updated);
|
|
380
|
+
await this.ctx.storage.put(`provider:${slug}`, updated);
|
|
381
|
+
return updated;
|
|
382
|
+
}
|
|
383
|
+
async deleteProvider(slug, options) {
|
|
384
|
+
await this.ensureInitialized();
|
|
385
|
+
const isRegistered = this.registeredProviders.has(slug);
|
|
386
|
+
const isBuiltIn = BUILT_IN_SLUGS.has(slug);
|
|
387
|
+
const wasDeleted = this.deletedSlugs.has(slug);
|
|
388
|
+
// If not registered, not built-in, and not previously deleted, nothing to delete
|
|
389
|
+
if (!isRegistered && !isBuiltIn) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
// If already deleted, return false
|
|
393
|
+
if (wasDeleted && !isRegistered) {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
// Protect built-in providers that haven't been re-registered
|
|
397
|
+
if (isBuiltIn && !isRegistered && !options?.force) {
|
|
398
|
+
throw new Error(`Cannot delete built-in provider '${slug}' without force flag`);
|
|
399
|
+
}
|
|
400
|
+
// Remove from registered providers
|
|
401
|
+
this.registeredProviders.delete(slug);
|
|
402
|
+
await this.ctx.storage.delete(`provider:${slug}`);
|
|
403
|
+
// Mark as deleted so getProvider won't return built-in
|
|
404
|
+
this.deletedSlugs.add(slug);
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
408
|
+
// ACCOUNT TYPE CRUD
|
|
409
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
410
|
+
async registerAccountType(type) {
|
|
411
|
+
await this.ensureInitialized();
|
|
412
|
+
const slug = type.slug;
|
|
413
|
+
const id = type.id || slug;
|
|
414
|
+
// Check if slug already exists in registered account types (not built-ins)
|
|
415
|
+
// This allows registering custom types that override built-ins
|
|
416
|
+
if (this.registeredAccountTypes.has(slug)) {
|
|
417
|
+
throw new Error(`Account type with slug '${slug}' already exists`);
|
|
418
|
+
}
|
|
419
|
+
const newType = {
|
|
420
|
+
...type,
|
|
421
|
+
id,
|
|
422
|
+
providers: type.providers ? [...type.providers] : [],
|
|
423
|
+
};
|
|
424
|
+
// Store in registered account types
|
|
425
|
+
this.registeredAccountTypes.set(slug, newType);
|
|
426
|
+
// Remove from deleted set (in case it was previously deleted)
|
|
427
|
+
this.deletedAccountTypeSlugs.delete(slug);
|
|
428
|
+
// Persist to storage
|
|
429
|
+
await this.ctx.storage.put(`accountType:${slug}`, newType);
|
|
430
|
+
return newType;
|
|
431
|
+
}
|
|
432
|
+
async getAccountType(slug) {
|
|
433
|
+
await this.ensureInitialized();
|
|
434
|
+
// If this slug was explicitly deleted, return null
|
|
435
|
+
if (this.deletedAccountTypeSlugs.has(slug)) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
// First check registered account types
|
|
439
|
+
const registered = this.registeredAccountTypes.get(slug);
|
|
440
|
+
if (registered) {
|
|
441
|
+
// Merge explicitly registered providers with dynamically discovered ones
|
|
442
|
+
const dynamicProviders = this.getProvidersForAccountType(slug);
|
|
443
|
+
const explicitProviders = registered.providers || [];
|
|
444
|
+
const allProviders = new Set([...explicitProviders, ...dynamicProviders]);
|
|
445
|
+
return { ...registered, providers: Array.from(allProviders) };
|
|
446
|
+
}
|
|
447
|
+
// Fall back to built-in account types
|
|
448
|
+
return this.getBuiltInAccountType(slug) || null;
|
|
449
|
+
}
|
|
450
|
+
async updateAccountType(slug, updates) {
|
|
451
|
+
await this.ensureInitialized();
|
|
452
|
+
// Cannot update slug
|
|
453
|
+
if (updates.slug && updates.slug !== slug) {
|
|
454
|
+
throw new Error('Cannot update slug: slug is immutable');
|
|
455
|
+
}
|
|
456
|
+
// Get existing account type (from registered or built-in)
|
|
457
|
+
const existing = this.registeredAccountTypes.get(slug) || this.getBuiltInAccountType(slug);
|
|
458
|
+
if (!existing) {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
// Merge updates (but don't allow slug or id to change)
|
|
462
|
+
const { slug: _slug, id: _id, ...safeUpdates } = updates;
|
|
463
|
+
const updated = {
|
|
464
|
+
...existing,
|
|
465
|
+
...safeUpdates,
|
|
466
|
+
id: existing.id,
|
|
467
|
+
slug: existing.slug,
|
|
468
|
+
};
|
|
469
|
+
// Store as registered (even for built-ins that get updated)
|
|
470
|
+
this.registeredAccountTypes.set(slug, updated);
|
|
471
|
+
await this.ctx.storage.put(`accountType:${slug}`, updated);
|
|
472
|
+
// Dynamically populate providers list
|
|
473
|
+
const providers = this.getProvidersForAccountType(slug);
|
|
474
|
+
return { ...updated, providers };
|
|
475
|
+
}
|
|
476
|
+
async deleteAccountType(slug, options) {
|
|
477
|
+
await this.ensureInitialized();
|
|
478
|
+
const isRegistered = this.registeredAccountTypes.has(slug);
|
|
479
|
+
const isBuiltIn = BUILT_IN_ACCOUNT_TYPE_SLUGS.has(slug);
|
|
480
|
+
const wasDeleted = this.deletedAccountTypeSlugs.has(slug);
|
|
481
|
+
// If not registered, not built-in, and not previously deleted, nothing to delete
|
|
482
|
+
if (!isRegistered && !isBuiltIn) {
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
// If already deleted, return false
|
|
486
|
+
if (wasDeleted && !isRegistered) {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
// Protect built-in account types that haven't been re-registered
|
|
490
|
+
if (isBuiltIn && !isRegistered && !options?.force) {
|
|
491
|
+
throw new Error(`Cannot delete built-in account type '${slug}' without force flag`);
|
|
492
|
+
}
|
|
493
|
+
// Remove from registered account types
|
|
494
|
+
this.registeredAccountTypes.delete(slug);
|
|
495
|
+
await this.ctx.storage.delete(`accountType:${slug}`);
|
|
496
|
+
// Mark as deleted so getAccountType won't return built-in
|
|
497
|
+
this.deletedAccountTypeSlugs.add(slug);
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
async listAccountTypes() {
|
|
501
|
+
await this.ensureInitialized();
|
|
502
|
+
const typesMap = new Map();
|
|
503
|
+
// Add built-in account types that haven't been deleted
|
|
504
|
+
for (const builtIn of BUILT_IN_ACCOUNT_TYPES) {
|
|
505
|
+
if (!this.deletedAccountTypeSlugs.has(builtIn.slug)) {
|
|
506
|
+
const providers = this.getProvidersForAccountType(builtIn.slug);
|
|
507
|
+
typesMap.set(builtIn.slug, { ...builtIn, providers });
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
// Add/override with registered account types
|
|
511
|
+
for (const [slug, type] of this.registeredAccountTypes) {
|
|
512
|
+
const providers = this.getProvidersForAccountType(slug);
|
|
513
|
+
typesMap.set(slug, { ...type, providers });
|
|
514
|
+
}
|
|
515
|
+
return Array.from(typesMap.values());
|
|
516
|
+
}
|
|
517
|
+
async listBuiltInAccountTypes() {
|
|
518
|
+
await this.ensureInitialized();
|
|
519
|
+
// Return copies of built-in account types with dynamic providers
|
|
520
|
+
return BUILT_IN_ACCOUNT_TYPES.map((t) => {
|
|
521
|
+
const providers = this.getProvidersForAccountType(t.slug);
|
|
522
|
+
return { ...t, providers };
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
async isBuiltInAccountType(slug) {
|
|
526
|
+
return BUILT_IN_ACCOUNT_TYPE_SLUGS.has(slug);
|
|
527
|
+
}
|
|
528
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
529
|
+
// LISTING
|
|
530
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
531
|
+
async listProviders(options) {
|
|
532
|
+
await this.ensureInitialized();
|
|
533
|
+
// Only return registered providers (not built-ins unless they were registered)
|
|
534
|
+
const all = Array.from(this.registeredProviders.values());
|
|
535
|
+
const limit = options?.limit ?? all.length;
|
|
536
|
+
const offset = options?.offset ?? 0;
|
|
537
|
+
return all.slice(offset, offset + limit);
|
|
538
|
+
}
|
|
539
|
+
async listProvidersByAccountType(accountType) {
|
|
540
|
+
await this.ensureInitialized();
|
|
541
|
+
// Search in registered providers only
|
|
542
|
+
return Array.from(this.registeredProviders.values()).filter((p) => p.accountType === accountType);
|
|
543
|
+
}
|
|
544
|
+
async searchProviders(query) {
|
|
545
|
+
await this.ensureInitialized();
|
|
546
|
+
const lowerQuery = query.toLowerCase();
|
|
547
|
+
// Search in registered providers only
|
|
548
|
+
return Array.from(this.registeredProviders.values()).filter((p) => p.name.toLowerCase().includes(lowerQuery) || p.slug.toLowerCase().includes(lowerQuery));
|
|
549
|
+
}
|
|
550
|
+
async getAccountTypes() {
|
|
551
|
+
await this.ensureInitialized();
|
|
552
|
+
const types = new Set();
|
|
553
|
+
// Get types from registered providers only
|
|
554
|
+
for (const provider of this.registeredProviders.values()) {
|
|
555
|
+
types.add(provider.accountType);
|
|
556
|
+
}
|
|
557
|
+
return Array.from(types);
|
|
558
|
+
}
|
|
559
|
+
async listBuiltInProviders() {
|
|
560
|
+
// Return copies of built-in providers
|
|
561
|
+
return BUILT_IN_PROVIDERS.map((p) => ({ ...p, actions: [...p.actions] }));
|
|
562
|
+
}
|
|
563
|
+
async isBuiltIn(slug) {
|
|
564
|
+
return BUILT_IN_SLUGS.has(slug);
|
|
565
|
+
}
|
|
566
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
567
|
+
// ACTION MANAGEMENT
|
|
568
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
569
|
+
async getActionsByScope(slug, scope) {
|
|
570
|
+
await this.ensureInitialized();
|
|
571
|
+
// Get provider from registered or built-in
|
|
572
|
+
const provider = this.registeredProviders.get(slug) || this.getBuiltInProvider(slug);
|
|
573
|
+
if (!provider) {
|
|
574
|
+
return [];
|
|
575
|
+
}
|
|
576
|
+
return provider.actions.filter((a) => a.scopes.includes(scope));
|
|
577
|
+
}
|
|
578
|
+
async addAction(slug, action) {
|
|
579
|
+
await this.ensureInitialized();
|
|
580
|
+
// Get provider (must be registered to modify)
|
|
581
|
+
const provider = this.registeredProviders.get(slug);
|
|
582
|
+
if (!provider) {
|
|
583
|
+
throw new Error(`Provider '${slug}' not found`);
|
|
584
|
+
}
|
|
585
|
+
provider.actions.push(action);
|
|
586
|
+
this.registeredProviders.set(slug, provider);
|
|
587
|
+
await this.ctx.storage.put(`provider:${slug}`, provider);
|
|
588
|
+
}
|
|
589
|
+
async removeAction(slug, actionName) {
|
|
590
|
+
await this.ensureInitialized();
|
|
591
|
+
// Get provider (must be registered to modify)
|
|
592
|
+
const provider = this.registeredProviders.get(slug);
|
|
593
|
+
if (!provider) {
|
|
594
|
+
throw new Error(`Provider '${slug}' not found`);
|
|
595
|
+
}
|
|
596
|
+
provider.actions = provider.actions.filter((a) => a.name !== actionName);
|
|
597
|
+
this.registeredProviders.set(slug, provider);
|
|
598
|
+
await this.ctx.storage.put(`provider:${slug}`, provider);
|
|
599
|
+
}
|
|
600
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
601
|
+
// PROVIDER ACTIONS SDK
|
|
602
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
603
|
+
/**
|
|
604
|
+
* Register a provider with extended action definitions (input/output schemas, rate limits)
|
|
605
|
+
*/
|
|
606
|
+
async registerProviderWithActions(provider) {
|
|
607
|
+
await this.ensureInitialized();
|
|
608
|
+
const slug = provider.slug;
|
|
609
|
+
// Store in providers with actions map
|
|
610
|
+
this.providersWithActions.set(slug, provider);
|
|
611
|
+
// Persist to storage
|
|
612
|
+
await this.ctx.storage.put(`providerWithActions:${slug}`, provider);
|
|
613
|
+
return provider;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Get a specific action from a provider
|
|
617
|
+
*/
|
|
618
|
+
async getAction(providerSlug, actionName) {
|
|
619
|
+
await this.ensureInitialized();
|
|
620
|
+
const provider = this.providersWithActions.get(providerSlug);
|
|
621
|
+
if (!provider) {
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
const action = provider.actions.find((a) => a.name === actionName);
|
|
625
|
+
return action || null;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Get all actions for a provider
|
|
629
|
+
*/
|
|
630
|
+
async getActions(providerSlug) {
|
|
631
|
+
await this.ensureInitialized();
|
|
632
|
+
const provider = this.providersWithActions.get(providerSlug);
|
|
633
|
+
if (!provider) {
|
|
634
|
+
return [];
|
|
635
|
+
}
|
|
636
|
+
return provider.actions;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Get the effective rate limit for an action (action-level or provider-level)
|
|
640
|
+
*/
|
|
641
|
+
async getEffectiveRateLimit(providerSlug, actionName) {
|
|
642
|
+
await this.ensureInitialized();
|
|
643
|
+
const provider = this.providersWithActions.get(providerSlug);
|
|
644
|
+
if (!provider) {
|
|
645
|
+
throw new Error(`Provider '${providerSlug}' not found`);
|
|
646
|
+
}
|
|
647
|
+
const action = provider.actions.find((a) => a.name === actionName);
|
|
648
|
+
// Action-level rate limit takes precedence
|
|
649
|
+
if (action?.rateLimit) {
|
|
650
|
+
return action.rateLimit;
|
|
651
|
+
}
|
|
652
|
+
// Fall back to provider-level rate limit
|
|
653
|
+
if (provider.rateLimit) {
|
|
654
|
+
return provider.rateLimit;
|
|
655
|
+
}
|
|
656
|
+
// Default rate limit if none specified
|
|
657
|
+
return { max: 1000, windowMs: 60000 };
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Validate input against an action's input schema
|
|
661
|
+
*/
|
|
662
|
+
async validateActionInput(providerSlug, actionName, input) {
|
|
663
|
+
await this.ensureInitialized();
|
|
664
|
+
const action = await this.getAction(providerSlug, actionName);
|
|
665
|
+
if (!action) {
|
|
666
|
+
return { valid: false, errors: [`Action '${actionName}' not found`] };
|
|
667
|
+
}
|
|
668
|
+
if (!action.inputSchema) {
|
|
669
|
+
// No schema means any input is valid
|
|
670
|
+
return { valid: true, errors: [] };
|
|
671
|
+
}
|
|
672
|
+
const errors = [];
|
|
673
|
+
// Validate required fields
|
|
674
|
+
if (action.inputSchema.required) {
|
|
675
|
+
for (const field of action.inputSchema.required) {
|
|
676
|
+
if (input[field] === undefined) {
|
|
677
|
+
errors.push(`${field} is required`);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
// Validate type of provided fields
|
|
682
|
+
if (action.inputSchema.properties) {
|
|
683
|
+
for (const [field, value] of Object.entries(input)) {
|
|
684
|
+
const schema = action.inputSchema.properties[field];
|
|
685
|
+
if (schema) {
|
|
686
|
+
const typeValid = this.validateType(value, schema);
|
|
687
|
+
if (!typeValid) {
|
|
688
|
+
errors.push(`${field} has invalid type`);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return { valid: errors.length === 0, errors };
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Helper to validate value against schema type
|
|
697
|
+
*/
|
|
698
|
+
validateType(value, schema) {
|
|
699
|
+
switch (schema.type) {
|
|
700
|
+
case 'string':
|
|
701
|
+
return typeof value === 'string';
|
|
702
|
+
case 'number':
|
|
703
|
+
return typeof value === 'number';
|
|
704
|
+
case 'boolean':
|
|
705
|
+
return typeof value === 'boolean';
|
|
706
|
+
case 'array':
|
|
707
|
+
return Array.isArray(value);
|
|
708
|
+
case 'object':
|
|
709
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
710
|
+
default:
|
|
711
|
+
return true;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Fetch token from Vault DO
|
|
716
|
+
*/
|
|
717
|
+
async fetchTokenFromVault(linkedAccountId) {
|
|
718
|
+
const vaultDO = this.env.VAULT_DO;
|
|
719
|
+
if (!vaultDO) {
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
const doId = vaultDO.idFromName ? vaultDO.idFromName(linkedAccountId) : linkedAccountId;
|
|
723
|
+
const stub = vaultDO.get(doId);
|
|
724
|
+
const response = await stub.fetch(new Request(`http://vault/token/${linkedAccountId}`));
|
|
725
|
+
if (!response.ok) {
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
// Clone response before reading to handle test mocks that reuse same Response object
|
|
729
|
+
try {
|
|
730
|
+
const data = (await response.clone().json());
|
|
731
|
+
return data;
|
|
732
|
+
}
|
|
733
|
+
catch {
|
|
734
|
+
// If clone fails, try reading directly
|
|
735
|
+
const data = (await response.json());
|
|
736
|
+
return data;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Refresh token in Vault DO
|
|
741
|
+
*/
|
|
742
|
+
async refreshTokenInVault(linkedAccountId) {
|
|
743
|
+
const vaultDO = this.env.VAULT_DO;
|
|
744
|
+
if (!vaultDO) {
|
|
745
|
+
return null;
|
|
746
|
+
}
|
|
747
|
+
const doId = vaultDO.idFromName ? vaultDO.idFromName(linkedAccountId) : linkedAccountId;
|
|
748
|
+
const stub = vaultDO.get(doId);
|
|
749
|
+
const response = await stub.fetch(new Request(`http://vault/token/${linkedAccountId}/refresh`, { method: 'POST' }));
|
|
750
|
+
if (!response.ok) {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
// Clone response before reading to handle test mocks that reuse same Response object
|
|
754
|
+
try {
|
|
755
|
+
const data = (await response.clone().json());
|
|
756
|
+
return data;
|
|
757
|
+
}
|
|
758
|
+
catch {
|
|
759
|
+
// If clone fails, try reading directly
|
|
760
|
+
const data = (await response.json());
|
|
761
|
+
return data;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Create a typed SDK for a provider
|
|
766
|
+
*/
|
|
767
|
+
async createSDK(providerSlug, linkedAccountId, options = {}) {
|
|
768
|
+
await this.ensureInitialized();
|
|
769
|
+
const provider = this.providersWithActions.get(providerSlug);
|
|
770
|
+
if (!provider) {
|
|
771
|
+
throw new Error(`Provider '${providerSlug}' not found`);
|
|
772
|
+
}
|
|
773
|
+
// Fetch initial token
|
|
774
|
+
const tokenData = await this.fetchTokenFromVault(linkedAccountId);
|
|
775
|
+
if (!tokenData) {
|
|
776
|
+
throw new Error(`Linked account '${linkedAccountId}' not found - no valid token`);
|
|
777
|
+
}
|
|
778
|
+
// Default options
|
|
779
|
+
const sdkOptions = {
|
|
780
|
+
maxRetries: options.maxRetries ?? 3,
|
|
781
|
+
retryDelayMs: options.retryDelayMs ?? 100,
|
|
782
|
+
timeout: options.timeout ?? 30000,
|
|
783
|
+
};
|
|
784
|
+
// Track rate limits per action
|
|
785
|
+
const rateLimitStates = new Map();
|
|
786
|
+
// Token state (mutable for refresh)
|
|
787
|
+
let currentToken = tokenData;
|
|
788
|
+
// Generate request ID
|
|
789
|
+
const generateRequestId = () => `sdk-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
790
|
+
// Helper to sleep
|
|
791
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
792
|
+
// Check and update rate limit
|
|
793
|
+
const checkRateLimit = async (actionName) => {
|
|
794
|
+
const rateLimit = await this.getEffectiveRateLimit(providerSlug, actionName);
|
|
795
|
+
const now = Date.now();
|
|
796
|
+
let state = rateLimitStates.get(actionName);
|
|
797
|
+
if (!state || now - state.windowStart > rateLimit.windowMs) {
|
|
798
|
+
// Reset window
|
|
799
|
+
state = { requestCount: 0, windowStart: now };
|
|
800
|
+
rateLimitStates.set(actionName, state);
|
|
801
|
+
}
|
|
802
|
+
if (state.requestCount >= rateLimit.max) {
|
|
803
|
+
return false; // Rate limited
|
|
804
|
+
}
|
|
805
|
+
state.requestCount++;
|
|
806
|
+
return true;
|
|
807
|
+
};
|
|
808
|
+
// Get rate limit state for an action
|
|
809
|
+
const getRateLimitState = (actionName) => {
|
|
810
|
+
return rateLimitStates.get(actionName);
|
|
811
|
+
};
|
|
812
|
+
// Execute action with retry logic
|
|
813
|
+
const executeAction = async (action, params, callOptions) => {
|
|
814
|
+
const requestId = generateRequestId();
|
|
815
|
+
// Validate input
|
|
816
|
+
const validation = await this.validateActionInput(providerSlug, action.name, params);
|
|
817
|
+
if (!validation.valid) {
|
|
818
|
+
throw new SDKError(`Validation failed: ${validation.errors.join(', ')}`, 'VALIDATION_ERROR', requestId, 400, false);
|
|
819
|
+
}
|
|
820
|
+
// Check rate limit
|
|
821
|
+
if (!callOptions?.queue) {
|
|
822
|
+
const allowed = await checkRateLimit(action.name);
|
|
823
|
+
if (!allowed) {
|
|
824
|
+
throw new SDKError('Rate limit exceeded', 'RATE_LIMITED', requestId, 429, true);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
// Build URL with path parameters
|
|
828
|
+
let url = action.endpoint;
|
|
829
|
+
const bodyParams = {};
|
|
830
|
+
for (const [key, value] of Object.entries(params)) {
|
|
831
|
+
const placeholder = `{${key}}`;
|
|
832
|
+
if (url.includes(placeholder)) {
|
|
833
|
+
url = url.replace(placeholder, String(value));
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
bodyParams[key] = value;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
// Retry loop
|
|
840
|
+
let lastError = null;
|
|
841
|
+
let retryCount = 0;
|
|
842
|
+
const maxRetries = sdkOptions.maxRetries;
|
|
843
|
+
while (retryCount <= maxRetries) {
|
|
844
|
+
try {
|
|
845
|
+
// Check if token is expired and refresh
|
|
846
|
+
if (currentToken.expiresAt < Date.now()) {
|
|
847
|
+
const newToken = await this.refreshTokenInVault(linkedAccountId);
|
|
848
|
+
if (newToken) {
|
|
849
|
+
currentToken = newToken;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
const fetchOptions = {
|
|
853
|
+
method: action.method,
|
|
854
|
+
headers: {
|
|
855
|
+
Authorization: `Bearer ${currentToken.accessToken}`,
|
|
856
|
+
'Content-Type': 'application/json',
|
|
857
|
+
},
|
|
858
|
+
};
|
|
859
|
+
if (action.method !== 'GET' && Object.keys(bodyParams).length > 0) {
|
|
860
|
+
fetchOptions.body = JSON.stringify(bodyParams);
|
|
861
|
+
}
|
|
862
|
+
const response = await fetch(`https://api.example.com.ai${url}`, fetchOptions);
|
|
863
|
+
// Handle response - clone before reading to handle test mocks that reuse Response objects
|
|
864
|
+
if (response.ok) {
|
|
865
|
+
let data;
|
|
866
|
+
try {
|
|
867
|
+
data = await response.clone().json();
|
|
868
|
+
}
|
|
869
|
+
catch {
|
|
870
|
+
data = await response.json();
|
|
871
|
+
}
|
|
872
|
+
if (callOptions?.includeRateLimit) {
|
|
873
|
+
const rateLimitInfo = {
|
|
874
|
+
remaining: parseInt(response.headers.get('X-RateLimit-Remaining') || '0', 10),
|
|
875
|
+
limit: parseInt(response.headers.get('X-RateLimit-Limit') || '0', 10),
|
|
876
|
+
resetAt: new Date(parseInt(response.headers.get('X-RateLimit-Reset') || '0', 10) * 1000),
|
|
877
|
+
};
|
|
878
|
+
return { data, rateLimit: rateLimitInfo };
|
|
879
|
+
}
|
|
880
|
+
return data;
|
|
881
|
+
}
|
|
882
|
+
// Get request ID from response
|
|
883
|
+
const responseRequestId = response.headers.get('X-Request-Id') || requestId;
|
|
884
|
+
// Handle specific status codes
|
|
885
|
+
if (response.status === 401) {
|
|
886
|
+
// Try to refresh token
|
|
887
|
+
const newToken = await this.refreshTokenInVault(linkedAccountId);
|
|
888
|
+
if (newToken && retryCount < maxRetries) {
|
|
889
|
+
currentToken = newToken;
|
|
890
|
+
retryCount++;
|
|
891
|
+
continue;
|
|
892
|
+
}
|
|
893
|
+
throw new SDKError('Unauthorized', 'UNAUTHORIZED', responseRequestId, 401, false);
|
|
894
|
+
}
|
|
895
|
+
if (response.status === 429) {
|
|
896
|
+
if (retryCount < maxRetries) {
|
|
897
|
+
const retryAfter = parseInt(response.headers.get('Retry-After') || '1', 10);
|
|
898
|
+
await sleep(retryAfter * 1000);
|
|
899
|
+
retryCount++;
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
throw new SDKError('Rate limited', 'RATE_LIMITED', responseRequestId, 429, true);
|
|
903
|
+
}
|
|
904
|
+
if (response.status >= 400 && response.status < 500) {
|
|
905
|
+
// Client errors (except 401, 429) are not retryable
|
|
906
|
+
throw new SDKError(`Client error: ${response.status}`, 'VALIDATION_ERROR', responseRequestId, response.status, false);
|
|
907
|
+
}
|
|
908
|
+
if (response.status >= 500) {
|
|
909
|
+
// Server errors are retryable
|
|
910
|
+
if (retryCount < maxRetries) {
|
|
911
|
+
const delay = sdkOptions.retryDelayMs * Math.pow(2, retryCount);
|
|
912
|
+
await sleep(delay);
|
|
913
|
+
retryCount++;
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
throw new SDKError(`Server error: ${response.status}`, 'SERVER_ERROR', responseRequestId, response.status, true);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
catch (error) {
|
|
920
|
+
if (error instanceof SDKError) {
|
|
921
|
+
throw error;
|
|
922
|
+
}
|
|
923
|
+
// Network error
|
|
924
|
+
if (retryCount < maxRetries) {
|
|
925
|
+
const delay = sdkOptions.retryDelayMs * Math.pow(2, retryCount);
|
|
926
|
+
await sleep(delay);
|
|
927
|
+
retryCount++;
|
|
928
|
+
lastError = error;
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
throw new SDKError(`Network error: ${error.message}`, 'NETWORK_ERROR', requestId, undefined, true);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
throw lastError || new SDKError('Max retries exceeded', 'SERVER_ERROR', requestId, undefined, true);
|
|
935
|
+
};
|
|
936
|
+
// Build SDK object with methods for each action
|
|
937
|
+
const sdk = {};
|
|
938
|
+
for (const action of provider.actions) {
|
|
939
|
+
sdk[action.name] = async (params, callOptions) => {
|
|
940
|
+
return executeAction(action, params, callOptions);
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
// Add metadata
|
|
944
|
+
sdk._metadata = {
|
|
945
|
+
provider: providerSlug,
|
|
946
|
+
linkedAccountId,
|
|
947
|
+
actions: provider.actions.map((a) => a.name),
|
|
948
|
+
options: sdkOptions,
|
|
949
|
+
};
|
|
950
|
+
// Add rate limit state getter
|
|
951
|
+
sdk.getRateLimitState = getRateLimitState;
|
|
952
|
+
return sdk;
|
|
953
|
+
}
|
|
954
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
955
|
+
// WEBHOOK VERIFICATION
|
|
956
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
957
|
+
async verifyWebhookSignature(slug, payload, signature) {
|
|
958
|
+
await this.ensureInitialized();
|
|
959
|
+
// Get provider from registered or built-in
|
|
960
|
+
const provider = this.registeredProviders.get(slug) || this.getBuiltInProvider(slug);
|
|
961
|
+
if (!provider || !provider.webhookConfig) {
|
|
962
|
+
return false;
|
|
963
|
+
}
|
|
964
|
+
const { algorithm, secretEnvVar } = provider.webhookConfig;
|
|
965
|
+
const secret = this.env[secretEnvVar];
|
|
966
|
+
if (!secret) {
|
|
967
|
+
return false;
|
|
968
|
+
}
|
|
969
|
+
try {
|
|
970
|
+
// Extract the signature hash part (e.g., "sha256=abc123" -> "abc123")
|
|
971
|
+
const [algo, hash] = signature.split('=');
|
|
972
|
+
if (!hash) {
|
|
973
|
+
return false;
|
|
974
|
+
}
|
|
975
|
+
// Verify algorithm matches
|
|
976
|
+
if (algo !== algorithm) {
|
|
977
|
+
return false;
|
|
978
|
+
}
|
|
979
|
+
// Compute expected signature using Web Crypto API
|
|
980
|
+
const encoder = new TextEncoder();
|
|
981
|
+
const key = await crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: algorithm === 'sha256' ? 'SHA-256' : 'SHA-1' }, false, ['sign']);
|
|
982
|
+
const signatureBuffer = await crypto.subtle.sign('HMAC', key, encoder.encode(payload));
|
|
983
|
+
const expectedHash = Array.from(new Uint8Array(signatureBuffer))
|
|
984
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
985
|
+
.join('');
|
|
986
|
+
// Constant-time comparison
|
|
987
|
+
if (hash.length !== expectedHash.length) {
|
|
988
|
+
return false;
|
|
989
|
+
}
|
|
990
|
+
let result = 0;
|
|
991
|
+
for (let i = 0; i < hash.length; i++) {
|
|
992
|
+
result |= hash.charCodeAt(i) ^ expectedHash.charCodeAt(i);
|
|
993
|
+
}
|
|
994
|
+
return result === 0;
|
|
995
|
+
}
|
|
996
|
+
catch {
|
|
997
|
+
return false;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1001
|
+
// HTTP API
|
|
1002
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1003
|
+
async fetch(request) {
|
|
1004
|
+
const url = new URL(request.url);
|
|
1005
|
+
const method = request.method;
|
|
1006
|
+
const path = url.pathname;
|
|
1007
|
+
try {
|
|
1008
|
+
// GET /providers
|
|
1009
|
+
if (method === 'GET' && path === '/providers') {
|
|
1010
|
+
const accountType = url.searchParams.get('accountType');
|
|
1011
|
+
const search = url.searchParams.get('search');
|
|
1012
|
+
let providers;
|
|
1013
|
+
if (accountType) {
|
|
1014
|
+
providers = await this.listProvidersByAccountType(accountType);
|
|
1015
|
+
}
|
|
1016
|
+
else if (search) {
|
|
1017
|
+
providers = await this.searchProviders(search);
|
|
1018
|
+
}
|
|
1019
|
+
else {
|
|
1020
|
+
providers = await this.listProviders();
|
|
1021
|
+
}
|
|
1022
|
+
return Response.json(providers);
|
|
1023
|
+
}
|
|
1024
|
+
// GET /providers/:slug
|
|
1025
|
+
const providerMatch = path.match(/^\/providers\/([^/]+)$/);
|
|
1026
|
+
if (method === 'GET' && providerMatch) {
|
|
1027
|
+
const slug = providerMatch[1];
|
|
1028
|
+
const provider = await this.getProvider(slug);
|
|
1029
|
+
if (!provider) {
|
|
1030
|
+
return new Response('Provider not found', { status: 404 });
|
|
1031
|
+
}
|
|
1032
|
+
return Response.json(provider);
|
|
1033
|
+
}
|
|
1034
|
+
// POST /providers
|
|
1035
|
+
if (method === 'POST' && path === '/providers') {
|
|
1036
|
+
const body = (await request.json());
|
|
1037
|
+
const provider = await this.registerProvider(body);
|
|
1038
|
+
return Response.json(provider, { status: 201 });
|
|
1039
|
+
}
|
|
1040
|
+
// PUT /providers/:slug
|
|
1041
|
+
if (method === 'PUT' && providerMatch) {
|
|
1042
|
+
const slug = providerMatch[1];
|
|
1043
|
+
const body = (await request.json());
|
|
1044
|
+
const provider = await this.updateProvider(slug, body);
|
|
1045
|
+
if (!provider) {
|
|
1046
|
+
return new Response('Provider not found', { status: 404 });
|
|
1047
|
+
}
|
|
1048
|
+
return Response.json(provider);
|
|
1049
|
+
}
|
|
1050
|
+
// DELETE /providers/:slug
|
|
1051
|
+
if (method === 'DELETE' && providerMatch) {
|
|
1052
|
+
const slug = providerMatch[1];
|
|
1053
|
+
const deleted = await this.deleteProvider(slug);
|
|
1054
|
+
if (!deleted) {
|
|
1055
|
+
return new Response('Provider not found', { status: 404 });
|
|
1056
|
+
}
|
|
1057
|
+
return Response.json({ success: true });
|
|
1058
|
+
}
|
|
1059
|
+
// POST /providers/:slug/verify-webhook
|
|
1060
|
+
const webhookMatch = path.match(/^\/providers\/([^/]+)\/verify-webhook$/);
|
|
1061
|
+
if (method === 'POST' && webhookMatch) {
|
|
1062
|
+
const slug = webhookMatch[1];
|
|
1063
|
+
const body = (await request.json());
|
|
1064
|
+
const valid = await this.verifyWebhookSignature(slug, body.payload, body.signature);
|
|
1065
|
+
return Response.json({ valid });
|
|
1066
|
+
}
|
|
1067
|
+
// GET /account-types - list all account types as objects
|
|
1068
|
+
if (method === 'GET' && path === '/account-types') {
|
|
1069
|
+
const types = await this.listAccountTypes();
|
|
1070
|
+
return Response.json(types);
|
|
1071
|
+
}
|
|
1072
|
+
// Account type routes
|
|
1073
|
+
const accountTypeMatch = path.match(/^\/account-types\/([^/]+)$/);
|
|
1074
|
+
// GET /account-types/:slug
|
|
1075
|
+
if (method === 'GET' && accountTypeMatch) {
|
|
1076
|
+
const slug = accountTypeMatch[1];
|
|
1077
|
+
const accountType = await this.getAccountType(slug);
|
|
1078
|
+
if (!accountType) {
|
|
1079
|
+
return new Response('Account type not found', { status: 404 });
|
|
1080
|
+
}
|
|
1081
|
+
return Response.json(accountType);
|
|
1082
|
+
}
|
|
1083
|
+
// POST /account-types
|
|
1084
|
+
if (method === 'POST' && path === '/account-types') {
|
|
1085
|
+
const body = (await request.json());
|
|
1086
|
+
// Check if this slug already exists (as built-in or registered)
|
|
1087
|
+
const existing = await this.getAccountType(body.slug);
|
|
1088
|
+
if (existing) {
|
|
1089
|
+
return Response.json({ error: `Account type with slug '${body.slug}' already exists` }, { status: 400 });
|
|
1090
|
+
}
|
|
1091
|
+
const accountType = await this.registerAccountType(body);
|
|
1092
|
+
return Response.json(accountType, { status: 201 });
|
|
1093
|
+
}
|
|
1094
|
+
// PUT /account-types/:slug
|
|
1095
|
+
if (method === 'PUT' && accountTypeMatch) {
|
|
1096
|
+
const slug = accountTypeMatch[1];
|
|
1097
|
+
const body = (await request.json());
|
|
1098
|
+
const accountType = await this.updateAccountType(slug, body);
|
|
1099
|
+
if (!accountType) {
|
|
1100
|
+
return new Response('Account type not found', { status: 404 });
|
|
1101
|
+
}
|
|
1102
|
+
return Response.json(accountType);
|
|
1103
|
+
}
|
|
1104
|
+
// DELETE /account-types/:slug
|
|
1105
|
+
if (method === 'DELETE' && accountTypeMatch) {
|
|
1106
|
+
const slug = accountTypeMatch[1];
|
|
1107
|
+
try {
|
|
1108
|
+
const deleted = await this.deleteAccountType(slug);
|
|
1109
|
+
if (!deleted) {
|
|
1110
|
+
return new Response('Account type not found', { status: 404 });
|
|
1111
|
+
}
|
|
1112
|
+
return Response.json({ success: true });
|
|
1113
|
+
}
|
|
1114
|
+
catch (error) {
|
|
1115
|
+
// Built-in account types can't be deleted without force
|
|
1116
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
1117
|
+
return Response.json({ error: message }, { status: 400 });
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
// GET /providers/:slug/actions - list all actions for a provider
|
|
1121
|
+
const actionsListMatch = path.match(/^\/providers\/([^/]+)\/actions$/);
|
|
1122
|
+
if (method === 'GET' && actionsListMatch) {
|
|
1123
|
+
const slug = actionsListMatch[1];
|
|
1124
|
+
const actions = await this.getActions(slug);
|
|
1125
|
+
return Response.json(actions);
|
|
1126
|
+
}
|
|
1127
|
+
// GET /providers/:slug/actions/:action - get single action
|
|
1128
|
+
const actionMatch = path.match(/^\/providers\/([^/]+)\/actions\/([^/]+)$/);
|
|
1129
|
+
if (method === 'GET' && actionMatch) {
|
|
1130
|
+
const slug = actionMatch[1];
|
|
1131
|
+
const actionName = actionMatch[2];
|
|
1132
|
+
const action = await this.getAction(slug, actionName);
|
|
1133
|
+
if (!action) {
|
|
1134
|
+
return new Response('Action not found', { status: 404 });
|
|
1135
|
+
}
|
|
1136
|
+
return Response.json(action);
|
|
1137
|
+
}
|
|
1138
|
+
// POST /providers/:slug/actions/:action/validate - validate action input
|
|
1139
|
+
const validateMatch = path.match(/^\/providers\/([^/]+)\/actions\/([^/]+)\/validate$/);
|
|
1140
|
+
if (method === 'POST' && validateMatch) {
|
|
1141
|
+
const slug = validateMatch[1];
|
|
1142
|
+
const actionName = validateMatch[2];
|
|
1143
|
+
const body = (await request.json());
|
|
1144
|
+
const validation = await this.validateActionInput(slug, actionName, body);
|
|
1145
|
+
return Response.json(validation);
|
|
1146
|
+
}
|
|
1147
|
+
// POST /providers/:slug/actions/:action/execute - execute action via SDK
|
|
1148
|
+
const executeMatch = path.match(/^\/providers\/([^/]+)\/actions\/([^/]+)\/execute$/);
|
|
1149
|
+
if (method === 'POST' && executeMatch) {
|
|
1150
|
+
const slug = executeMatch[1];
|
|
1151
|
+
const actionName = executeMatch[2];
|
|
1152
|
+
const body = (await request.json());
|
|
1153
|
+
const sdk = await this.createSDK(slug, body.linkedAccountId);
|
|
1154
|
+
const actionFn = sdk[actionName];
|
|
1155
|
+
if (!actionFn) {
|
|
1156
|
+
return new Response('Action not found', { status: 404 });
|
|
1157
|
+
}
|
|
1158
|
+
const result = await actionFn(body.params);
|
|
1159
|
+
return Response.json(result);
|
|
1160
|
+
}
|
|
1161
|
+
// Health check
|
|
1162
|
+
if (path === '/health') {
|
|
1163
|
+
return Response.json({ status: 'ok', ns: this.ns });
|
|
1164
|
+
}
|
|
1165
|
+
return new Response('Not Found', { status: 404 });
|
|
1166
|
+
}
|
|
1167
|
+
catch (error) {
|
|
1168
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
1169
|
+
return Response.json({ error: message }, { status: 400 });
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
export default IntegrationsDO;
|
|
1174
|
+
//# sourceMappingURL=IntegrationsDO.js.map
|