@dotdo/do 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/README.md +400 -0
- package/dist/ai/embeddings.d.ts +129 -0
- package/dist/ai/embeddings.d.ts.map +1 -0
- package/dist/ai/embeddings.js +217 -0
- package/dist/ai/embeddings.js.map +1 -0
- package/dist/ai/gateway.d.ts +139 -0
- package/dist/ai/gateway.d.ts.map +1 -0
- package/dist/ai/gateway.js +179 -0
- package/dist/ai/gateway.js.map +1 -0
- package/dist/ai/image.d.ts +140 -0
- package/dist/ai/image.d.ts.map +1 -0
- package/dist/ai/image.js +199 -0
- package/dist/ai/image.js.map +1 -0
- package/dist/ai/index.d.ts +98 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +223 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/models.d.ts +81 -0
- package/dist/ai/models.d.ts.map +1 -0
- package/dist/ai/models.js +537 -0
- package/dist/ai/models.js.map +1 -0
- package/dist/ai/text.d.ts +176 -0
- package/dist/ai/text.d.ts.map +1 -0
- package/dist/ai/text.js +253 -0
- package/dist/ai/text.js.map +1 -0
- package/dist/ai/voice/agents.d.ts +224 -0
- package/dist/ai/voice/agents.d.ts.map +1 -0
- package/dist/ai/voice/agents.js +375 -0
- package/dist/ai/voice/agents.js.map +1 -0
- package/dist/ai/voice/campaigns.d.ts +307 -0
- package/dist/ai/voice/campaigns.d.ts.map +1 -0
- package/dist/ai/voice/campaigns.js +739 -0
- package/dist/ai/voice/campaigns.js.map +1 -0
- package/dist/ai/voice/index.d.ts +21 -0
- package/dist/ai/voice/index.d.ts.map +1 -0
- package/dist/ai/voice/index.js +42 -0
- package/dist/ai/voice/index.js.map +1 -0
- package/dist/ai/voice/providers.d.ts +283 -0
- package/dist/ai/voice/providers.d.ts.map +1 -0
- package/dist/ai/voice/providers.js +286 -0
- package/dist/ai/voice/providers.js.map +1 -0
- package/dist/ai/voice/sessions.d.ts +294 -0
- package/dist/ai/voice/sessions.d.ts.map +1 -0
- package/dist/ai/voice/sessions.js +531 -0
- package/dist/ai/voice/sessions.js.map +1 -0
- package/dist/ai/voice/tools.d.ts +242 -0
- package/dist/ai/voice/tools.d.ts.map +1 -0
- package/dist/ai/voice/tools.js +370 -0
- package/dist/ai/voice/tools.js.map +1 -0
- package/dist/ai/voice/tts.d.ts +173 -0
- package/dist/ai/voice/tts.d.ts.map +1 -0
- package/dist/ai/voice/tts.js +252 -0
- package/dist/ai/voice/tts.js.map +1 -0
- package/dist/ai/voice/webrtc.d.ts +228 -0
- package/dist/ai/voice/webrtc.d.ts.map +1 -0
- package/dist/ai/voice/webrtc.js +372 -0
- package/dist/ai/voice/webrtc.js.map +1 -0
- package/dist/api/index.d.ts +103 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +191 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/mcp/handlers.d.ts +25 -0
- package/dist/api/mcp/handlers.d.ts.map +1 -0
- package/dist/api/mcp/handlers.js +422 -0
- package/dist/api/mcp/handlers.js.map +1 -0
- package/dist/api/mcp/index.d.ts +113 -0
- package/dist/api/mcp/index.d.ts.map +1 -0
- package/dist/api/mcp/index.js +141 -0
- package/dist/api/mcp/index.js.map +1 -0
- package/dist/api/middleware/auth.d.ts +65 -0
- package/dist/api/middleware/auth.d.ts.map +1 -0
- package/dist/api/middleware/auth.js +271 -0
- package/dist/api/middleware/auth.js.map +1 -0
- package/dist/api/middleware/cors.d.ts +62 -0
- package/dist/api/middleware/cors.d.ts.map +1 -0
- package/dist/api/middleware/cors.js +225 -0
- package/dist/api/middleware/cors.js.map +1 -0
- package/dist/api/middleware/index.d.ts +60 -0
- package/dist/api/middleware/index.d.ts.map +1 -0
- package/dist/api/middleware/index.js +175 -0
- package/dist/api/middleware/index.js.map +1 -0
- package/dist/api/middleware/rateLimit.d.ts +84 -0
- package/dist/api/middleware/rateLimit.d.ts.map +1 -0
- package/dist/api/middleware/rateLimit.js +321 -0
- package/dist/api/middleware/rateLimit.js.map +1 -0
- package/dist/api/routes/ai.d.ts +17 -0
- package/dist/api/routes/ai.d.ts.map +1 -0
- package/dist/api/routes/ai.js +430 -0
- package/dist/api/routes/ai.js.map +1 -0
- package/dist/api/routes/do.d.ts +17 -0
- package/dist/api/routes/do.d.ts.map +1 -0
- package/dist/api/routes/do.js +458 -0
- package/dist/api/routes/do.js.map +1 -0
- package/dist/api/routes/functions.d.ts +111 -0
- package/dist/api/routes/functions.d.ts.map +1 -0
- package/dist/api/routes/functions.js +548 -0
- package/dist/api/routes/functions.js.map +1 -0
- package/dist/api/routes/health.d.ts +16 -0
- package/dist/api/routes/health.d.ts.map +1 -0
- package/dist/api/routes/health.js +163 -0
- package/dist/api/routes/health.js.map +1 -0
- package/dist/api/routes/index.d.ts +41 -0
- package/dist/api/routes/index.d.ts.map +1 -0
- package/dist/api/routes/index.js +275 -0
- package/dist/api/routes/index.js.map +1 -0
- package/dist/api/routes/nouns.d.ts +26 -0
- package/dist/api/routes/nouns.d.ts.map +1 -0
- package/dist/api/routes/nouns.js +456 -0
- package/dist/api/routes/nouns.js.map +1 -0
- package/dist/api/routes/orgs.d.ts +17 -0
- package/dist/api/routes/orgs.d.ts.map +1 -0
- package/dist/api/routes/orgs.js +560 -0
- package/dist/api/routes/orgs.js.map +1 -0
- package/dist/api/routes/relationships.d.ts +30 -0
- package/dist/api/routes/relationships.d.ts.map +1 -0
- package/dist/api/routes/relationships.js +360 -0
- package/dist/api/routes/relationships.js.map +1 -0
- package/dist/api/routes/roles.d.ts +17 -0
- package/dist/api/routes/roles.d.ts.map +1 -0
- package/dist/api/routes/roles.js +721 -0
- package/dist/api/routes/roles.js.map +1 -0
- package/dist/api/routes/things.d.ts +27 -0
- package/dist/api/routes/things.d.ts.map +1 -0
- package/dist/api/routes/things.js +568 -0
- package/dist/api/routes/things.js.map +1 -0
- package/dist/api/routes/users.d.ts +17 -0
- package/dist/api/routes/users.d.ts.map +1 -0
- package/dist/api/routes/users.js +401 -0
- package/dist/api/routes/users.js.map +1 -0
- package/dist/api/routes/verbs.d.ts +31 -0
- package/dist/api/routes/verbs.d.ts.map +1 -0
- package/dist/api/routes/verbs.js +505 -0
- package/dist/api/routes/verbs.js.map +1 -0
- package/dist/api/routes/workflows.d.ts +44 -0
- package/dist/api/routes/workflows.d.ts.map +1 -0
- package/dist/api/routes/workflows.js +521 -0
- package/dist/api/routes/workflows.js.map +1 -0
- package/dist/api/types.d.ts +370 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +11 -0
- package/dist/api/types.js.map +1 -0
- package/dist/db/cdc/events.d.ts +201 -0
- package/dist/db/cdc/events.d.ts.map +1 -0
- package/dist/db/cdc/events.js +271 -0
- package/dist/db/cdc/events.js.map +1 -0
- package/dist/db/cdc/index.d.ts +13 -0
- package/dist/db/cdc/index.d.ts.map +1 -0
- package/dist/db/cdc/index.js +16 -0
- package/dist/db/cdc/index.js.map +1 -0
- package/dist/db/cdc/replay.d.ts +388 -0
- package/dist/db/cdc/replay.d.ts.map +1 -0
- package/dist/db/cdc/replay.js +469 -0
- package/dist/db/cdc/replay.js.map +1 -0
- package/dist/db/cdc/storage.d.ts +567 -0
- package/dist/db/cdc/storage.d.ts.map +1 -0
- package/dist/db/cdc/storage.js +856 -0
- package/dist/db/cdc/storage.js.map +1 -0
- package/dist/db/cdc/streaming.d.ts +459 -0
- package/dist/db/cdc/streaming.d.ts.map +1 -0
- package/dist/db/cdc/streaming.js +636 -0
- package/dist/db/cdc/streaming.js.map +1 -0
- package/dist/db/collections/actions.d.ts +440 -0
- package/dist/db/collections/actions.d.ts.map +1 -0
- package/dist/db/collections/actions.js +631 -0
- package/dist/db/collections/actions.js.map +1 -0
- package/dist/db/collections/base.d.ts +342 -0
- package/dist/db/collections/base.d.ts.map +1 -0
- package/dist/db/collections/base.js +510 -0
- package/dist/db/collections/base.js.map +1 -0
- package/dist/db/collections/index.d.ts +50 -0
- package/dist/db/collections/index.d.ts.map +1 -0
- package/dist/db/collections/index.js +48 -0
- package/dist/db/collections/index.js.map +1 -0
- package/dist/db/collections/nouns.d.ts +260 -0
- package/dist/db/collections/nouns.d.ts.map +1 -0
- package/dist/db/collections/nouns.js +273 -0
- package/dist/db/collections/nouns.js.map +1 -0
- package/dist/db/collections/relationships.d.ts +484 -0
- package/dist/db/collections/relationships.d.ts.map +1 -0
- package/dist/db/collections/relationships.js +815 -0
- package/dist/db/collections/relationships.js.map +1 -0
- package/dist/db/collections/things.d.ts +439 -0
- package/dist/db/collections/things.d.ts.map +1 -0
- package/dist/db/collections/things.js +603 -0
- package/dist/db/collections/things.js.map +1 -0
- package/dist/db/collections/verbs.d.ts +308 -0
- package/dist/db/collections/verbs.d.ts.map +1 -0
- package/dist/db/collections/verbs.js +480 -0
- package/dist/db/collections/verbs.js.map +1 -0
- package/dist/db/index.d.ts +14 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +23 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/storage/cold.d.ts +313 -0
- package/dist/db/storage/cold.d.ts.map +1 -0
- package/dist/db/storage/cold.js +319 -0
- package/dist/db/storage/cold.js.map +1 -0
- package/dist/db/storage/hot.d.ts +340 -0
- package/dist/db/storage/hot.d.ts.map +1 -0
- package/dist/db/storage/hot.js +333 -0
- package/dist/db/storage/hot.js.map +1 -0
- package/dist/db/storage/index.d.ts +242 -0
- package/dist/db/storage/index.d.ts.map +1 -0
- package/dist/db/storage/index.js +109 -0
- package/dist/db/storage/index.js.map +1 -0
- package/dist/db/storage/snapshots.d.ts +342 -0
- package/dist/db/storage/snapshots.d.ts.map +1 -0
- package/dist/db/storage/snapshots.js +298 -0
- package/dist/db/storage/snapshots.js.map +1 -0
- package/dist/db/storage/vortex.d.ts +324 -0
- package/dist/db/storage/vortex.d.ts.map +1 -0
- package/dist/db/storage/vortex.js +365 -0
- package/dist/db/storage/vortex.js.map +1 -0
- package/dist/db/storage/warm.d.ts +306 -0
- package/dist/db/storage/warm.d.ts.map +1 -0
- package/dist/db/storage/warm.js +339 -0
- package/dist/db/storage/warm.js.map +1 -0
- package/dist/do/DigitalObject.d.ts +595 -0
- package/dist/do/DigitalObject.d.ts.map +1 -0
- package/dist/do/DigitalObject.js +971 -0
- package/dist/do/DigitalObject.js.map +1 -0
- package/dist/do/business/financial/accounting.d.ts +436 -0
- package/dist/do/business/financial/accounting.d.ts.map +1 -0
- package/dist/do/business/financial/accounting.js +476 -0
- package/dist/do/business/financial/accounting.js.map +1 -0
- package/dist/do/business/financial/index.d.ts +15 -0
- package/dist/do/business/financial/index.d.ts.map +1 -0
- package/dist/do/business/financial/index.js +20 -0
- package/dist/do/business/financial/index.js.map +1 -0
- package/dist/do/business/financial/metrics.d.ts +370 -0
- package/dist/do/business/financial/metrics.d.ts.map +1 -0
- package/dist/do/business/financial/metrics.js +376 -0
- package/dist/do/business/financial/metrics.js.map +1 -0
- package/dist/do/business/financial/payments.d.ts +397 -0
- package/dist/do/business/financial/payments.d.ts.map +1 -0
- package/dist/do/business/financial/payments.js +395 -0
- package/dist/do/business/financial/payments.js.map +1 -0
- package/dist/do/business/financial/reports.d.ts +284 -0
- package/dist/do/business/financial/reports.d.ts.map +1 -0
- package/dist/do/business/financial/reports.js +347 -0
- package/dist/do/business/financial/reports.js.map +1 -0
- package/dist/do/business/financial/stripe.d.ts +254 -0
- package/dist/do/business/financial/stripe.d.ts.map +1 -0
- package/dist/do/business/financial/stripe.js +261 -0
- package/dist/do/business/financial/stripe.js.map +1 -0
- package/dist/do/business/financial/subscriptions.d.ts +402 -0
- package/dist/do/business/financial/subscriptions.d.ts.map +1 -0
- package/dist/do/business/financial/subscriptions.js +349 -0
- package/dist/do/business/financial/subscriptions.js.map +1 -0
- package/dist/do/business/index.d.ts +9 -0
- package/dist/do/business/index.d.ts.map +1 -0
- package/dist/do/business/index.js +10 -0
- package/dist/do/business/index.js.map +1 -0
- package/dist/do/colo/followers.d.ts +194 -0
- package/dist/do/colo/followers.d.ts.map +1 -0
- package/dist/do/colo/followers.js +224 -0
- package/dist/do/colo/followers.js.map +1 -0
- package/dist/do/colo/fork.d.ts +103 -0
- package/dist/do/colo/fork.d.ts.map +1 -0
- package/dist/do/colo/fork.js +143 -0
- package/dist/do/colo/fork.js.map +1 -0
- package/dist/do/colo/index.d.ts +181 -0
- package/dist/do/colo/index.d.ts.map +1 -0
- package/dist/do/colo/index.js +145 -0
- package/dist/do/colo/index.js.map +1 -0
- package/dist/do/colo/info.d.ts +106 -0
- package/dist/do/colo/info.d.ts.map +1 -0
- package/dist/do/colo/info.js +196 -0
- package/dist/do/colo/info.js.map +1 -0
- package/dist/do/colo/migrate.d.ts +161 -0
- package/dist/do/colo/migrate.d.ts.map +1 -0
- package/dist/do/colo/migrate.js +190 -0
- package/dist/do/colo/migrate.js.map +1 -0
- package/dist/do/colo/routing.d.ts +182 -0
- package/dist/do/colo/routing.d.ts.map +1 -0
- package/dist/do/colo/routing.js +254 -0
- package/dist/do/colo/routing.js.map +1 -0
- package/dist/do/domains/dns.d.ts +269 -0
- package/dist/do/domains/dns.d.ts.map +1 -0
- package/dist/do/domains/dns.js +215 -0
- package/dist/do/domains/dns.js.map +1 -0
- package/dist/do/domains/index.d.ts +40 -0
- package/dist/do/domains/index.d.ts.map +1 -0
- package/dist/do/domains/index.js +61 -0
- package/dist/do/domains/index.js.map +1 -0
- package/dist/do/domains/routing.d.ts +263 -0
- package/dist/do/domains/routing.d.ts.map +1 -0
- package/dist/do/domains/routing.js +362 -0
- package/dist/do/domains/routing.js.map +1 -0
- package/dist/do/domains/ssl.d.ts +217 -0
- package/dist/do/domains/ssl.d.ts.map +1 -0
- package/dist/do/domains/ssl.js +231 -0
- package/dist/do/domains/ssl.js.map +1 -0
- package/dist/do/domains/subdomains.d.ts +207 -0
- package/dist/do/domains/subdomains.d.ts.map +1 -0
- package/dist/do/domains/subdomains.js +223 -0
- package/dist/do/domains/subdomains.js.map +1 -0
- package/dist/do/domains/tlds.d.ts +175 -0
- package/dist/do/domains/tlds.d.ts.map +1 -0
- package/dist/do/domains/tlds.js +188 -0
- package/dist/do/domains/tlds.js.map +1 -0
- package/dist/do/domains/validation.d.ts +164 -0
- package/dist/do/domains/validation.d.ts.map +1 -0
- package/dist/do/domains/validation.js +290 -0
- package/dist/do/domains/validation.js.map +1 -0
- package/dist/do/hibernation.d.ts +385 -0
- package/dist/do/hibernation.d.ts.map +1 -0
- package/dist/do/hibernation.js +518 -0
- package/dist/do/hibernation.js.map +1 -0
- package/dist/do/index.d.ts +19 -0
- package/dist/do/index.d.ts.map +1 -0
- package/dist/do/index.js +23 -0
- package/dist/do/index.js.map +1 -0
- package/dist/do/state.d.ts +336 -0
- package/dist/do/state.d.ts.map +1 -0
- package/dist/do/state.js +290 -0
- package/dist/do/state.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/rpc/client.d.ts +426 -0
- package/dist/rpc/client.d.ts.map +1 -0
- package/dist/rpc/client.js +826 -0
- package/dist/rpc/client.js.map +1 -0
- package/dist/rpc/index.d.ts +19 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +23 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/rpc/methods.d.ts +364 -0
- package/dist/rpc/methods.d.ts.map +1 -0
- package/dist/rpc/methods.js +557 -0
- package/dist/rpc/methods.js.map +1 -0
- package/dist/rpc/protocol.d.ts +310 -0
- package/dist/rpc/protocol.d.ts.map +1 -0
- package/dist/rpc/protocol.js +672 -0
- package/dist/rpc/protocol.js.map +1 -0
- package/dist/rpc/routes.d.ts +332 -0
- package/dist/rpc/routes.d.ts.map +1 -0
- package/dist/rpc/routes.js +633 -0
- package/dist/rpc/routes.js.map +1 -0
- package/dist/rpc/server.d.ts +380 -0
- package/dist/rpc/server.d.ts.map +1 -0
- package/dist/rpc/server.js +850 -0
- package/dist/rpc/server.js.map +1 -0
- package/dist/sdk/auth.d.ts +201 -0
- package/dist/sdk/auth.d.ts.map +1 -0
- package/dist/sdk/auth.js +343 -0
- package/dist/sdk/auth.js.map +1 -0
- package/dist/sdk/client.d.ts +123 -0
- package/dist/sdk/client.d.ts.map +1 -0
- package/dist/sdk/client.js +403 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/index.d.ts +123 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +230 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/rpc.d.ts +275 -0
- package/dist/sdk/rpc.d.ts.map +1 -0
- package/dist/sdk/rpc.js +249 -0
- package/dist/sdk/rpc.js.map +1 -0
- package/dist/sdk/transport.d.ts +283 -0
- package/dist/sdk/transport.d.ts.map +1 -0
- package/dist/sdk/transport.js +661 -0
- package/dist/sdk/transport.js.map +1 -0
- package/dist/sdk/types.d.ts +265 -0
- package/dist/sdk/types.d.ts.map +1 -0
- package/dist/sdk/types.js +27 -0
- package/dist/sdk/types.js.map +1 -0
- package/dist/types/ai.d.ts +533 -0
- package/dist/types/ai.d.ts.map +1 -0
- package/dist/types/ai.js +18 -0
- package/dist/types/ai.js.map +1 -0
- package/dist/types/app.d.ts +371 -0
- package/dist/types/app.d.ts.map +1 -0
- package/dist/types/app.js +151 -0
- package/dist/types/app.js.map +1 -0
- package/dist/types/business.d.ts +482 -0
- package/dist/types/business.d.ts.map +1 -0
- package/dist/types/business.js +60 -0
- package/dist/types/business.js.map +1 -0
- package/dist/types/cascade.d.ts +323 -0
- package/dist/types/cascade.d.ts.map +1 -0
- package/dist/types/cascade.js +82 -0
- package/dist/types/cascade.js.map +1 -0
- package/dist/types/collections.d.ts +704 -0
- package/dist/types/collections.d.ts.map +1 -0
- package/dist/types/collections.js +23 -0
- package/dist/types/collections.js.map +1 -0
- package/dist/types/colo.d.ts +171 -0
- package/dist/types/colo.d.ts.map +1 -0
- package/dist/types/colo.js +63 -0
- package/dist/types/colo.js.map +1 -0
- package/dist/types/communication.d.ts +595 -0
- package/dist/types/communication.d.ts.map +1 -0
- package/dist/types/communication.js +16 -0
- package/dist/types/communication.js.map +1 -0
- package/dist/types/content.d.ts +286 -0
- package/dist/types/content.d.ts.map +1 -0
- package/dist/types/content.js +8 -0
- package/dist/types/content.js.map +1 -0
- package/dist/types/context.d.ts +407 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/context.js +36 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/databases.d.ts +377 -0
- package/dist/types/databases.d.ts.map +1 -0
- package/dist/types/databases.js +14 -0
- package/dist/types/databases.js.map +1 -0
- package/dist/types/domains.d.ts +132 -0
- package/dist/types/domains.d.ts.map +1 -0
- package/dist/types/domains.js +107 -0
- package/dist/types/domains.js.map +1 -0
- package/dist/types/execution.d.ts +381 -0
- package/dist/types/execution.d.ts.map +1 -0
- package/dist/types/execution.js +40 -0
- package/dist/types/execution.js.map +1 -0
- package/dist/types/financial.d.ts +608 -0
- package/dist/types/financial.d.ts.map +1 -0
- package/dist/types/financial.js +12 -0
- package/dist/types/financial.js.map +1 -0
- package/dist/types/functions.d.ts +215 -0
- package/dist/types/functions.d.ts.map +1 -0
- package/dist/types/functions.js +15 -0
- package/dist/types/functions.js.map +1 -0
- package/dist/types/git.d.ts +299 -0
- package/dist/types/git.d.ts.map +1 -0
- package/dist/types/git.js +17 -0
- package/dist/types/git.js.map +1 -0
- package/dist/types/identity.d.ts +141 -0
- package/dist/types/identity.d.ts.map +1 -0
- package/dist/types/identity.js +54 -0
- package/dist/types/identity.js.map +1 -0
- package/dist/types/index.d.ts +40 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +65 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/integrations.d.ts +356 -0
- package/dist/types/integrations.d.ts.map +1 -0
- package/dist/types/integrations.js +19 -0
- package/dist/types/integrations.js.map +1 -0
- package/dist/types/mdxui.d.ts +1955 -0
- package/dist/types/mdxui.d.ts.map +1 -0
- package/dist/types/mdxui.js +751 -0
- package/dist/types/mdxui.js.map +1 -0
- package/dist/types/observability.d.ts +315 -0
- package/dist/types/observability.d.ts.map +1 -0
- package/dist/types/observability.js +13 -0
- package/dist/types/observability.js.map +1 -0
- package/dist/types/rpc.d.ts +339 -0
- package/dist/types/rpc.d.ts.map +1 -0
- package/dist/types/rpc.js +24 -0
- package/dist/types/rpc.js.map +1 -0
- package/dist/types/saas.d.ts +678 -0
- package/dist/types/saas.d.ts.map +1 -0
- package/dist/types/saas.js +59 -0
- package/dist/types/saas.js.map +1 -0
- package/dist/types/service.d.ts +676 -0
- package/dist/types/service.d.ts.map +1 -0
- package/dist/types/service.js +69 -0
- package/dist/types/service.js.map +1 -0
- package/dist/types/site.d.ts +317 -0
- package/dist/types/site.d.ts.map +1 -0
- package/dist/types/site.js +203 -0
- package/dist/types/site.js.map +1 -0
- package/dist/types/startup.d.ts +576 -0
- package/dist/types/startup.d.ts.map +1 -0
- package/dist/types/startup.js +59 -0
- package/dist/types/startup.js.map +1 -0
- package/dist/types/storage.d.ts +276 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +35 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/types/telephony.d.ts +458 -0
- package/dist/types/telephony.d.ts.map +1 -0
- package/dist/types/telephony.js +19 -0
- package/dist/types/telephony.js.map +1 -0
- package/dist/types/tenant.d.ts +708 -0
- package/dist/types/tenant.d.ts.map +1 -0
- package/dist/types/tenant.js +103 -0
- package/dist/types/tenant.js.map +1 -0
- package/dist/types/voice-ai.d.ts +459 -0
- package/dist/types/voice-ai.d.ts.map +1 -0
- package/dist/types/voice-ai.js +32 -0
- package/dist/types/voice-ai.js.map +1 -0
- package/package.json +143 -0
|
@@ -0,0 +1,739 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound Campaign Management
|
|
3
|
+
*
|
|
4
|
+
* Manages automated outbound calling campaigns with
|
|
5
|
+
* scheduling, contact management, and real-time statistics.
|
|
6
|
+
*
|
|
7
|
+
* @module ai/voice/campaigns
|
|
8
|
+
*/
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Campaign Manager
|
|
11
|
+
// =============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Outbound campaign manager
|
|
14
|
+
*
|
|
15
|
+
* Manages automated outbound calling campaigns with scheduling,
|
|
16
|
+
* contact list management, retry logic, and statistics.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const manager = new VoiceCampaignManager(storage, sessionManager, agentManager)
|
|
21
|
+
*
|
|
22
|
+
* // Create a campaign
|
|
23
|
+
* const campaign = await manager.create({
|
|
24
|
+
* name: 'Q4 Follow-up',
|
|
25
|
+
* agentId: 'vagent_sales',
|
|
26
|
+
* contacts: [
|
|
27
|
+
* { phone: '+1-555-0001', name: 'Alice' },
|
|
28
|
+
* { phone: '+1-555-0002', name: 'Bob' },
|
|
29
|
+
* ],
|
|
30
|
+
* schedule: {
|
|
31
|
+
* startDate: Date.now(),
|
|
32
|
+
* callingHours: { start: '09:00', end: '17:00' },
|
|
33
|
+
* daysOfWeek: [1, 2, 3, 4, 5],
|
|
34
|
+
* timezone: 'America/New_York',
|
|
35
|
+
* maxConcurrent: 5,
|
|
36
|
+
* },
|
|
37
|
+
* settings: {
|
|
38
|
+
* maxAttempts: 3,
|
|
39
|
+
* retryDelay: 60,
|
|
40
|
+
* voicemailDetection: true,
|
|
41
|
+
* callerId: '+1-555-0100',
|
|
42
|
+
* },
|
|
43
|
+
* })
|
|
44
|
+
*
|
|
45
|
+
* // Start the campaign
|
|
46
|
+
* await manager.start(campaign.id)
|
|
47
|
+
*
|
|
48
|
+
* // Monitor stats
|
|
49
|
+
* const stats = await manager.getStats(campaign.id)
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export class VoiceCampaignManager {
|
|
53
|
+
storage;
|
|
54
|
+
sessionManager;
|
|
55
|
+
agentManager;
|
|
56
|
+
eventHandlers = new Map();
|
|
57
|
+
/**
|
|
58
|
+
* Create a campaign manager
|
|
59
|
+
*
|
|
60
|
+
* @param storage - DO storage interface
|
|
61
|
+
* @param sessionManager - Voice session manager
|
|
62
|
+
* @param agentManager - Voice agent manager
|
|
63
|
+
*/
|
|
64
|
+
constructor(storage, sessionManager, agentManager) {
|
|
65
|
+
this.storage = storage;
|
|
66
|
+
this.sessionManager = sessionManager;
|
|
67
|
+
this.agentManager = agentManager;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create a new campaign
|
|
71
|
+
*
|
|
72
|
+
* @param options - Campaign options
|
|
73
|
+
* @returns Created campaign
|
|
74
|
+
*/
|
|
75
|
+
async create(options) {
|
|
76
|
+
// Validate agent exists
|
|
77
|
+
const agent = await this.agentManager.get(options.agentId);
|
|
78
|
+
if (!agent) {
|
|
79
|
+
throw new Error(`Voice agent not found: ${options.agentId}`);
|
|
80
|
+
}
|
|
81
|
+
const campaignId = `vcamp_${generateId()}`;
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
// Process contacts
|
|
84
|
+
const contacts = options.contacts.map((c, index) => ({
|
|
85
|
+
id: `contact_${generateId()}`,
|
|
86
|
+
phone: c.phone,
|
|
87
|
+
name: c.name,
|
|
88
|
+
context: c.context,
|
|
89
|
+
status: 'Pending',
|
|
90
|
+
}));
|
|
91
|
+
const campaign = {
|
|
92
|
+
id: campaignId,
|
|
93
|
+
name: options.name,
|
|
94
|
+
agentId: options.agentId,
|
|
95
|
+
contacts,
|
|
96
|
+
schedule: options.schedule,
|
|
97
|
+
status: 'Draft',
|
|
98
|
+
settings: options.settings,
|
|
99
|
+
stats: {
|
|
100
|
+
totalContacts: contacts.length,
|
|
101
|
+
called: 0,
|
|
102
|
+
completed: 0,
|
|
103
|
+
transferred: 0,
|
|
104
|
+
voicemail: 0,
|
|
105
|
+
noAnswer: 0,
|
|
106
|
+
failed: 0,
|
|
107
|
+
avgDuration: 0,
|
|
108
|
+
totalCost: 0,
|
|
109
|
+
},
|
|
110
|
+
createdAt: now,
|
|
111
|
+
};
|
|
112
|
+
await this.storage.put(`voice_campaign:${campaignId}`, campaign);
|
|
113
|
+
return campaign;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get a campaign by ID
|
|
117
|
+
*
|
|
118
|
+
* @param id - Campaign ID
|
|
119
|
+
* @returns Campaign or null if not found
|
|
120
|
+
*/
|
|
121
|
+
async get(id) {
|
|
122
|
+
const result = await this.storage.get(`voice_campaign:${id}`);
|
|
123
|
+
return result ?? null;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Update a campaign
|
|
127
|
+
*
|
|
128
|
+
* Can only update draft or paused campaigns.
|
|
129
|
+
*
|
|
130
|
+
* @param id - Campaign ID
|
|
131
|
+
* @param options - Fields to update
|
|
132
|
+
* @returns Updated campaign
|
|
133
|
+
*/
|
|
134
|
+
async update(id, options) {
|
|
135
|
+
const campaign = await this.get(id);
|
|
136
|
+
if (!campaign) {
|
|
137
|
+
throw new Error(`Campaign not found: ${id}`);
|
|
138
|
+
}
|
|
139
|
+
if (campaign.status === 'Running' || campaign.status === 'Completed') {
|
|
140
|
+
throw new Error(`Cannot update campaign in status: ${campaign.status}`);
|
|
141
|
+
}
|
|
142
|
+
const updated = {
|
|
143
|
+
...campaign,
|
|
144
|
+
name: options.name ?? campaign.name,
|
|
145
|
+
schedule: options.schedule ? { ...campaign.schedule, ...options.schedule } : campaign.schedule,
|
|
146
|
+
settings: options.settings ? { ...campaign.settings, ...options.settings } : campaign.settings,
|
|
147
|
+
};
|
|
148
|
+
await this.storage.put(`voice_campaign:${id}`, updated);
|
|
149
|
+
return updated;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Add contacts to a campaign
|
|
153
|
+
*
|
|
154
|
+
* Can only add contacts to draft or paused campaigns.
|
|
155
|
+
*
|
|
156
|
+
* @param id - Campaign ID
|
|
157
|
+
* @param contacts - Contacts to add
|
|
158
|
+
* @returns Updated campaign
|
|
159
|
+
*/
|
|
160
|
+
async addContacts(id, contacts) {
|
|
161
|
+
const campaign = await this.get(id);
|
|
162
|
+
if (!campaign) {
|
|
163
|
+
throw new Error(`Campaign not found: ${id}`);
|
|
164
|
+
}
|
|
165
|
+
if (campaign.status === 'Running' || campaign.status === 'Completed') {
|
|
166
|
+
throw new Error(`Cannot add contacts to campaign in status: ${campaign.status}`);
|
|
167
|
+
}
|
|
168
|
+
const newContacts = contacts.map((c) => ({
|
|
169
|
+
id: `contact_${generateId()}`,
|
|
170
|
+
phone: c.phone,
|
|
171
|
+
name: c.name,
|
|
172
|
+
context: c.context,
|
|
173
|
+
status: 'Pending',
|
|
174
|
+
}));
|
|
175
|
+
const updated = {
|
|
176
|
+
...campaign,
|
|
177
|
+
contacts: [...campaign.contacts, ...newContacts],
|
|
178
|
+
stats: campaign.stats ? {
|
|
179
|
+
...campaign.stats,
|
|
180
|
+
totalContacts: campaign.contacts.length + newContacts.length,
|
|
181
|
+
} : undefined,
|
|
182
|
+
};
|
|
183
|
+
await this.storage.put(`voice_campaign:${id}`, updated);
|
|
184
|
+
return updated;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Remove a contact from a campaign
|
|
188
|
+
*
|
|
189
|
+
* @param id - Campaign ID
|
|
190
|
+
* @param contactId - Contact ID
|
|
191
|
+
* @returns Updated campaign
|
|
192
|
+
*/
|
|
193
|
+
async removeContact(id, contactId) {
|
|
194
|
+
const campaign = await this.get(id);
|
|
195
|
+
if (!campaign) {
|
|
196
|
+
throw new Error(`Campaign not found: ${id}`);
|
|
197
|
+
}
|
|
198
|
+
if (campaign.status === 'Running' || campaign.status === 'Completed') {
|
|
199
|
+
throw new Error(`Cannot remove contacts from campaign in status: ${campaign.status}`);
|
|
200
|
+
}
|
|
201
|
+
const updated = {
|
|
202
|
+
...campaign,
|
|
203
|
+
contacts: campaign.contacts.filter((c) => c.id !== contactId),
|
|
204
|
+
stats: campaign.stats ? {
|
|
205
|
+
...campaign.stats,
|
|
206
|
+
totalContacts: campaign.contacts.length - 1,
|
|
207
|
+
} : undefined,
|
|
208
|
+
};
|
|
209
|
+
await this.storage.put(`voice_campaign:${id}`, updated);
|
|
210
|
+
return updated;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Start a campaign
|
|
214
|
+
*
|
|
215
|
+
* @param id - Campaign ID
|
|
216
|
+
* @returns Updated campaign
|
|
217
|
+
*/
|
|
218
|
+
async start(id) {
|
|
219
|
+
const campaign = await this.get(id);
|
|
220
|
+
if (!campaign) {
|
|
221
|
+
throw new Error(`Campaign not found: ${id}`);
|
|
222
|
+
}
|
|
223
|
+
if (campaign.status !== 'Draft' && campaign.status !== 'Scheduled' && campaign.status !== 'Paused') {
|
|
224
|
+
throw new Error(`Cannot start campaign in status: ${campaign.status}`);
|
|
225
|
+
}
|
|
226
|
+
const updated = {
|
|
227
|
+
...campaign,
|
|
228
|
+
status: 'Running',
|
|
229
|
+
startedAt: campaign.startedAt ?? Date.now(),
|
|
230
|
+
};
|
|
231
|
+
await this.storage.put(`voice_campaign:${id}`, updated);
|
|
232
|
+
// Emit started event
|
|
233
|
+
await this.emit(id, 'started', { campaignId: id });
|
|
234
|
+
// Schedule first batch of calls
|
|
235
|
+
await this.scheduleNextBatch(id);
|
|
236
|
+
return updated;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Pause a running campaign
|
|
240
|
+
*
|
|
241
|
+
* @param id - Campaign ID
|
|
242
|
+
* @returns Updated campaign
|
|
243
|
+
*/
|
|
244
|
+
async pause(id) {
|
|
245
|
+
const campaign = await this.get(id);
|
|
246
|
+
if (!campaign) {
|
|
247
|
+
throw new Error(`Campaign not found: ${id}`);
|
|
248
|
+
}
|
|
249
|
+
if (campaign.status !== 'Running') {
|
|
250
|
+
throw new Error(`Cannot pause campaign in status: ${campaign.status}`);
|
|
251
|
+
}
|
|
252
|
+
const updated = {
|
|
253
|
+
...campaign,
|
|
254
|
+
status: 'Paused',
|
|
255
|
+
};
|
|
256
|
+
await this.storage.put(`voice_campaign:${id}`, updated);
|
|
257
|
+
await this.emit(id, 'paused', { campaignId: id });
|
|
258
|
+
return updated;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Resume a paused campaign
|
|
262
|
+
*
|
|
263
|
+
* @param id - Campaign ID
|
|
264
|
+
* @returns Updated campaign
|
|
265
|
+
*/
|
|
266
|
+
async resume(id) {
|
|
267
|
+
const campaign = await this.get(id);
|
|
268
|
+
if (!campaign) {
|
|
269
|
+
throw new Error(`Campaign not found: ${id}`);
|
|
270
|
+
}
|
|
271
|
+
if (campaign.status !== 'Paused') {
|
|
272
|
+
throw new Error(`Cannot resume campaign in status: ${campaign.status}`);
|
|
273
|
+
}
|
|
274
|
+
const updated = {
|
|
275
|
+
...campaign,
|
|
276
|
+
status: 'Running',
|
|
277
|
+
};
|
|
278
|
+
await this.storage.put(`voice_campaign:${id}`, updated);
|
|
279
|
+
await this.emit(id, 'resumed', { campaignId: id });
|
|
280
|
+
// Resume calling
|
|
281
|
+
await this.scheduleNextBatch(id);
|
|
282
|
+
return updated;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Stop a campaign (mark as completed)
|
|
286
|
+
*
|
|
287
|
+
* @param id - Campaign ID
|
|
288
|
+
* @returns Updated campaign
|
|
289
|
+
*/
|
|
290
|
+
async stop(id) {
|
|
291
|
+
const campaign = await this.get(id);
|
|
292
|
+
if (!campaign) {
|
|
293
|
+
throw new Error(`Campaign not found: ${id}`);
|
|
294
|
+
}
|
|
295
|
+
const updated = {
|
|
296
|
+
...campaign,
|
|
297
|
+
status: 'Completed',
|
|
298
|
+
completedAt: Date.now(),
|
|
299
|
+
};
|
|
300
|
+
await this.storage.put(`voice_campaign:${id}`, updated);
|
|
301
|
+
await this.emit(id, 'completed', { campaignId: id });
|
|
302
|
+
return updated;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Delete a campaign
|
|
306
|
+
*
|
|
307
|
+
* @param id - Campaign ID
|
|
308
|
+
* @returns True if deleted
|
|
309
|
+
*/
|
|
310
|
+
async delete(id) {
|
|
311
|
+
const campaign = await this.get(id);
|
|
312
|
+
if (!campaign) {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
if (campaign.status === 'Running') {
|
|
316
|
+
throw new Error('Cannot delete a running campaign');
|
|
317
|
+
}
|
|
318
|
+
await this.storage.delete(`voice_campaign:${id}`);
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* List campaigns
|
|
323
|
+
*
|
|
324
|
+
* @param options - Filter and pagination options
|
|
325
|
+
* @returns List of campaigns
|
|
326
|
+
*/
|
|
327
|
+
async list(options = {}) {
|
|
328
|
+
const { status, agentId, limit = 50, offset = 0 } = options;
|
|
329
|
+
const allCampaigns = await this.storage.list({ prefix: 'voice_campaign:' });
|
|
330
|
+
let items = [];
|
|
331
|
+
for (const [, campaign] of allCampaigns) {
|
|
332
|
+
if (status && campaign.status !== status)
|
|
333
|
+
continue;
|
|
334
|
+
if (agentId && campaign.agentId !== agentId)
|
|
335
|
+
continue;
|
|
336
|
+
items.push(campaign);
|
|
337
|
+
}
|
|
338
|
+
// Sort by createdAt descending
|
|
339
|
+
items.sort((a, b) => b.createdAt - a.createdAt);
|
|
340
|
+
const total = items.length;
|
|
341
|
+
items = items.slice(offset, offset + limit);
|
|
342
|
+
return {
|
|
343
|
+
items,
|
|
344
|
+
total,
|
|
345
|
+
hasMore: offset + items.length < total,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Get campaign statistics
|
|
350
|
+
*
|
|
351
|
+
* @param id - Campaign ID
|
|
352
|
+
* @returns Campaign statistics
|
|
353
|
+
*/
|
|
354
|
+
async getStats(id) {
|
|
355
|
+
const campaign = await this.get(id);
|
|
356
|
+
if (!campaign) {
|
|
357
|
+
throw new Error(`Campaign not found: ${id}`);
|
|
358
|
+
}
|
|
359
|
+
// Recalculate stats from contacts
|
|
360
|
+
const stats = {
|
|
361
|
+
totalContacts: campaign.contacts.length,
|
|
362
|
+
called: 0,
|
|
363
|
+
completed: 0,
|
|
364
|
+
transferred: 0,
|
|
365
|
+
voicemail: 0,
|
|
366
|
+
noAnswer: 0,
|
|
367
|
+
failed: 0,
|
|
368
|
+
avgDuration: 0,
|
|
369
|
+
totalCost: 0,
|
|
370
|
+
};
|
|
371
|
+
let totalDuration = 0;
|
|
372
|
+
let callsWithDuration = 0;
|
|
373
|
+
for (const contact of campaign.contacts) {
|
|
374
|
+
if (contact.status === 'Completed' || contact.status === 'Failed') {
|
|
375
|
+
stats.called++;
|
|
376
|
+
}
|
|
377
|
+
if (contact.status === 'Completed') {
|
|
378
|
+
stats.completed++;
|
|
379
|
+
// Get session for duration/cost
|
|
380
|
+
if (contact.sessionId) {
|
|
381
|
+
const session = await this.sessionManager.get(contact.sessionId);
|
|
382
|
+
if (session) {
|
|
383
|
+
if (session.duration) {
|
|
384
|
+
totalDuration += session.duration;
|
|
385
|
+
callsWithDuration++;
|
|
386
|
+
}
|
|
387
|
+
if (session.cost) {
|
|
388
|
+
stats.totalCost += session.cost.total;
|
|
389
|
+
}
|
|
390
|
+
if (session.outcome?.type === 'Transferred') {
|
|
391
|
+
stats.transferred++;
|
|
392
|
+
}
|
|
393
|
+
if (session.outcome?.type === 'Voicemail') {
|
|
394
|
+
stats.voicemail++;
|
|
395
|
+
}
|
|
396
|
+
if (session.outcome?.type === 'NoAnswer') {
|
|
397
|
+
stats.noAnswer++;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (contact.status === 'Failed') {
|
|
403
|
+
stats.failed++;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
stats.avgDuration = callsWithDuration > 0 ? totalDuration / callsWithDuration : 0;
|
|
407
|
+
return stats;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Schedule the next batch of calls
|
|
411
|
+
*
|
|
412
|
+
* @param id - Campaign ID
|
|
413
|
+
*/
|
|
414
|
+
async scheduleNextBatch(id) {
|
|
415
|
+
const campaign = await this.get(id);
|
|
416
|
+
if (!campaign || campaign.status !== 'Running') {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
// Check calling hours
|
|
420
|
+
if (campaign.schedule && !isWithinCallingHours(campaign.schedule)) {
|
|
421
|
+
// Schedule alarm for next calling window
|
|
422
|
+
const nextWindow = getNextCallingWindow(campaign.schedule);
|
|
423
|
+
// TODO: Set DO alarm
|
|
424
|
+
// await this.ctx.storage.setAlarm(nextWindow)
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
// Get pending contacts up to maxConcurrent
|
|
428
|
+
const maxConcurrent = campaign.schedule?.maxConcurrent ?? 1;
|
|
429
|
+
const pendingContacts = campaign.contacts
|
|
430
|
+
.filter((c) => c.status === 'Pending')
|
|
431
|
+
.slice(0, maxConcurrent);
|
|
432
|
+
if (pendingContacts.length === 0) {
|
|
433
|
+
// No more contacts, mark as completed
|
|
434
|
+
await this.stop(id);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
// Start calls for each contact
|
|
438
|
+
for (const contact of pendingContacts) {
|
|
439
|
+
await this.startContactCall(id, contact);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Start a call for a campaign contact
|
|
444
|
+
*
|
|
445
|
+
* @param campaignId - Campaign ID
|
|
446
|
+
* @param contact - Contact to call
|
|
447
|
+
*/
|
|
448
|
+
async startContactCall(campaignId, contact) {
|
|
449
|
+
const campaign = await this.get(campaignId);
|
|
450
|
+
if (!campaign)
|
|
451
|
+
return;
|
|
452
|
+
try {
|
|
453
|
+
// Update contact status
|
|
454
|
+
await this.updateContactStatus(campaignId, contact.id, 'Calling');
|
|
455
|
+
// Start the call
|
|
456
|
+
const session = await this.sessionManager.startOutbound({
|
|
457
|
+
agentId: campaign.agentId,
|
|
458
|
+
phone: contact.phone,
|
|
459
|
+
context: {
|
|
460
|
+
campaignId,
|
|
461
|
+
contactId: contact.id,
|
|
462
|
+
contactName: contact.name,
|
|
463
|
+
...contact.context,
|
|
464
|
+
},
|
|
465
|
+
metadata: {
|
|
466
|
+
campaignId,
|
|
467
|
+
contactId: contact.id,
|
|
468
|
+
},
|
|
469
|
+
});
|
|
470
|
+
// Update contact with session ID
|
|
471
|
+
await this.updateContactSession(campaignId, contact.id, session.id);
|
|
472
|
+
await this.emit(campaignId, 'contact_called', {
|
|
473
|
+
campaignId,
|
|
474
|
+
contactId: contact.id,
|
|
475
|
+
sessionId: session.id,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
// Mark contact as failed
|
|
480
|
+
await this.updateContactStatus(campaignId, contact.id, 'Failed');
|
|
481
|
+
await this.emit(campaignId, 'contact_failed', {
|
|
482
|
+
campaignId,
|
|
483
|
+
contactId: contact.id,
|
|
484
|
+
error: error instanceof Error ? error.message : String(error),
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Update contact status
|
|
490
|
+
*/
|
|
491
|
+
async updateContactStatus(campaignId, contactId, status) {
|
|
492
|
+
const campaign = await this.get(campaignId);
|
|
493
|
+
if (!campaign)
|
|
494
|
+
return;
|
|
495
|
+
const updated = {
|
|
496
|
+
...campaign,
|
|
497
|
+
contacts: campaign.contacts.map((c) => c.id === contactId ? { ...c, status } : c),
|
|
498
|
+
};
|
|
499
|
+
await this.storage.put(`voice_campaign:${campaignId}`, updated);
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Update contact with session ID
|
|
503
|
+
*/
|
|
504
|
+
async updateContactSession(campaignId, contactId, sessionId) {
|
|
505
|
+
const campaign = await this.get(campaignId);
|
|
506
|
+
if (!campaign)
|
|
507
|
+
return;
|
|
508
|
+
const updated = {
|
|
509
|
+
...campaign,
|
|
510
|
+
contacts: campaign.contacts.map((c) => c.id === contactId ? { ...c, sessionId } : c),
|
|
511
|
+
};
|
|
512
|
+
await this.storage.put(`voice_campaign:${campaignId}`, updated);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Handle session completion (called from webhook processor)
|
|
516
|
+
*
|
|
517
|
+
* @param campaignId - Campaign ID
|
|
518
|
+
* @param contactId - Contact ID
|
|
519
|
+
* @param outcome - Call outcome
|
|
520
|
+
*/
|
|
521
|
+
async handleSessionComplete(campaignId, contactId, outcome) {
|
|
522
|
+
await this.updateContactStatus(campaignId, contactId, outcome);
|
|
523
|
+
await this.emit(campaignId, outcome === 'Completed' ? 'contact_completed' : 'contact_failed', {
|
|
524
|
+
campaignId,
|
|
525
|
+
contactId,
|
|
526
|
+
});
|
|
527
|
+
// Update stats
|
|
528
|
+
await this.emit(campaignId, 'stats_updated', await this.getStats(campaignId));
|
|
529
|
+
// Schedule next batch
|
|
530
|
+
await this.scheduleNextBatch(campaignId);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Subscribe to campaign events
|
|
534
|
+
*
|
|
535
|
+
* @param campaignId - Campaign ID
|
|
536
|
+
* @param event - Event type
|
|
537
|
+
* @param handler - Event handler
|
|
538
|
+
* @returns Unsubscribe function
|
|
539
|
+
*/
|
|
540
|
+
on(campaignId, event, handler) {
|
|
541
|
+
const key = `${campaignId}:${event}`;
|
|
542
|
+
if (!this.eventHandlers.has(key)) {
|
|
543
|
+
this.eventHandlers.set(key, new Set());
|
|
544
|
+
}
|
|
545
|
+
this.eventHandlers.get(key).add(handler);
|
|
546
|
+
return () => {
|
|
547
|
+
this.eventHandlers.get(key)?.delete(handler);
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Watch campaign stats (returns async iterator)
|
|
552
|
+
*
|
|
553
|
+
* @param campaignId - Campaign ID
|
|
554
|
+
* @returns Async iterator of stats updates
|
|
555
|
+
*/
|
|
556
|
+
async *watchStats(campaignId) {
|
|
557
|
+
// Initial stats
|
|
558
|
+
yield await this.getStats(campaignId);
|
|
559
|
+
// Create a channel for stats updates
|
|
560
|
+
const queue = [];
|
|
561
|
+
let resolve = null;
|
|
562
|
+
const unsubscribe = this.on(campaignId, 'stats_updated', (stats) => {
|
|
563
|
+
queue.push(stats);
|
|
564
|
+
if (resolve) {
|
|
565
|
+
resolve();
|
|
566
|
+
resolve = null;
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
try {
|
|
570
|
+
while (true) {
|
|
571
|
+
if (queue.length > 0) {
|
|
572
|
+
yield queue.shift();
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
// Wait for next update
|
|
576
|
+
await new Promise((r) => { resolve = r; });
|
|
577
|
+
}
|
|
578
|
+
// Check if campaign is still running
|
|
579
|
+
const campaign = await this.get(campaignId);
|
|
580
|
+
if (!campaign || campaign.status === 'Completed') {
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
finally {
|
|
586
|
+
unsubscribe();
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Emit a campaign event
|
|
591
|
+
*/
|
|
592
|
+
async emit(campaignId, event, data) {
|
|
593
|
+
const key = `${campaignId}:${event}`;
|
|
594
|
+
const handlers = this.eventHandlers.get(key);
|
|
595
|
+
if (handlers) {
|
|
596
|
+
for (const handler of handlers) {
|
|
597
|
+
await handler(data);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
// =============================================================================
|
|
603
|
+
// Helper Functions
|
|
604
|
+
// =============================================================================
|
|
605
|
+
/**
|
|
606
|
+
* Generate a random ID
|
|
607
|
+
*/
|
|
608
|
+
function generateId() {
|
|
609
|
+
// TODO: Use nanoid
|
|
610
|
+
return Math.random().toString(36).substring(2, 15);
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Check if current time is within calling hours
|
|
614
|
+
*/
|
|
615
|
+
function isWithinCallingHours(schedule) {
|
|
616
|
+
const now = new Date();
|
|
617
|
+
// Check day of week
|
|
618
|
+
const dayOfWeek = now.getDay();
|
|
619
|
+
if (!schedule.daysOfWeek.includes(dayOfWeek)) {
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
// Parse calling hours
|
|
623
|
+
const [startHour, startMin] = schedule.callingHours.start.split(':').map(Number);
|
|
624
|
+
const [endHour, endMin] = schedule.callingHours.end.split(':').map(Number);
|
|
625
|
+
// Get current time in campaign timezone (simplified - should use proper timezone lib)
|
|
626
|
+
const currentHour = now.getHours();
|
|
627
|
+
const currentMin = now.getMinutes();
|
|
628
|
+
const currentMinutes = currentHour * 60 + currentMin;
|
|
629
|
+
const startMinutes = startHour * 60 + startMin;
|
|
630
|
+
const endMinutes = endHour * 60 + endMin;
|
|
631
|
+
return currentMinutes >= startMinutes && currentMinutes < endMinutes;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Get next calling window start time
|
|
635
|
+
*/
|
|
636
|
+
function getNextCallingWindow(schedule) {
|
|
637
|
+
const now = new Date();
|
|
638
|
+
// Find next valid day
|
|
639
|
+
for (let i = 0; i < 7; i++) {
|
|
640
|
+
const checkDate = new Date(now.getTime() + i * 24 * 60 * 60 * 1000);
|
|
641
|
+
const dayOfWeek = checkDate.getDay();
|
|
642
|
+
if (schedule.daysOfWeek.includes(dayOfWeek)) {
|
|
643
|
+
// Set to start of calling hours
|
|
644
|
+
const [startHour, startMin] = schedule.callingHours.start.split(':').map(Number);
|
|
645
|
+
checkDate.setHours(startHour, startMin, 0, 0);
|
|
646
|
+
// If today and past calling hours, skip to next valid day
|
|
647
|
+
if (i === 0 && checkDate.getTime() < now.getTime()) {
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
return checkDate.getTime();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
// Fallback to tomorrow
|
|
654
|
+
return now.getTime() + 24 * 60 * 60 * 1000;
|
|
655
|
+
}
|
|
656
|
+
// =============================================================================
|
|
657
|
+
// Singleton Access
|
|
658
|
+
// =============================================================================
|
|
659
|
+
let defaultManager = null;
|
|
660
|
+
/**
|
|
661
|
+
* Voice campaigns singleton access
|
|
662
|
+
*/
|
|
663
|
+
export const VoiceCampaigns = {
|
|
664
|
+
/**
|
|
665
|
+
* Initialize with dependencies
|
|
666
|
+
*/
|
|
667
|
+
init(storage, sessionManager, agentManager) {
|
|
668
|
+
defaultManager = new VoiceCampaignManager(storage, sessionManager, agentManager);
|
|
669
|
+
},
|
|
670
|
+
/**
|
|
671
|
+
* Create a campaign
|
|
672
|
+
*/
|
|
673
|
+
async create(options) {
|
|
674
|
+
if (!defaultManager)
|
|
675
|
+
throw new Error('VoiceCampaigns not initialized');
|
|
676
|
+
return defaultManager.create(options);
|
|
677
|
+
},
|
|
678
|
+
/**
|
|
679
|
+
* Get a campaign
|
|
680
|
+
*/
|
|
681
|
+
async get(id) {
|
|
682
|
+
if (!defaultManager)
|
|
683
|
+
throw new Error('VoiceCampaigns not initialized');
|
|
684
|
+
return defaultManager.get(id);
|
|
685
|
+
},
|
|
686
|
+
/**
|
|
687
|
+
* Start a campaign
|
|
688
|
+
*/
|
|
689
|
+
async start(id) {
|
|
690
|
+
if (!defaultManager)
|
|
691
|
+
throw new Error('VoiceCampaigns not initialized');
|
|
692
|
+
return defaultManager.start(id);
|
|
693
|
+
},
|
|
694
|
+
/**
|
|
695
|
+
* Pause a campaign
|
|
696
|
+
*/
|
|
697
|
+
async pause(id) {
|
|
698
|
+
if (!defaultManager)
|
|
699
|
+
throw new Error('VoiceCampaigns not initialized');
|
|
700
|
+
return defaultManager.pause(id);
|
|
701
|
+
},
|
|
702
|
+
/**
|
|
703
|
+
* Resume a campaign
|
|
704
|
+
*/
|
|
705
|
+
async resume(id) {
|
|
706
|
+
if (!defaultManager)
|
|
707
|
+
throw new Error('VoiceCampaigns not initialized');
|
|
708
|
+
return defaultManager.resume(id);
|
|
709
|
+
},
|
|
710
|
+
/**
|
|
711
|
+
* Get campaign stats
|
|
712
|
+
*/
|
|
713
|
+
async getStats(id) {
|
|
714
|
+
if (!defaultManager)
|
|
715
|
+
throw new Error('VoiceCampaigns not initialized');
|
|
716
|
+
return defaultManager.getStats(id);
|
|
717
|
+
},
|
|
718
|
+
/**
|
|
719
|
+
* List campaigns
|
|
720
|
+
*/
|
|
721
|
+
async list(options) {
|
|
722
|
+
if (!defaultManager)
|
|
723
|
+
throw new Error('VoiceCampaigns not initialized');
|
|
724
|
+
return defaultManager.list(options);
|
|
725
|
+
},
|
|
726
|
+
/**
|
|
727
|
+
* Watch campaign stats
|
|
728
|
+
*/
|
|
729
|
+
watchStats(id) {
|
|
730
|
+
if (!defaultManager)
|
|
731
|
+
throw new Error('VoiceCampaigns not initialized');
|
|
732
|
+
return defaultManager.watchStats(id);
|
|
733
|
+
},
|
|
734
|
+
};
|
|
735
|
+
// =============================================================================
|
|
736
|
+
// Type Exports
|
|
737
|
+
// =============================================================================
|
|
738
|
+
// Note: DurableObjectStorage is a Cloudflare Workers type, imported at runtime
|
|
739
|
+
//# sourceMappingURL=campaigns.js.map
|