vellum 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -2
- package/bun.lock +5 -2
- package/package.json +4 -2
- package/scripts/capture-x-graphql.ts +562 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -1
- package/scripts/test.sh +5 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +133 -34
- package/src/__tests__/account-registry.test.ts +2 -1
- package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
- package/src/__tests__/asset-materialize-tool.test.ts +16 -15
- package/src/__tests__/asset-search-tool.test.ts +23 -22
- package/src/__tests__/attachments-store.test.ts +56 -127
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
- package/src/__tests__/browser-skill-endstate.test.ts +4 -3
- package/src/__tests__/call-bridge.test.ts +385 -0
- package/src/__tests__/call-constants.test.ts +40 -0
- package/src/__tests__/call-orchestrator.test.ts +130 -4
- package/src/__tests__/call-recovery.test.ts +518 -0
- package/src/__tests__/call-routes-http.test.ts +459 -0
- package/src/__tests__/call-state-machine.test.ts +143 -0
- package/src/__tests__/call-store.test.ts +216 -1
- package/src/__tests__/cli-discover.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +148 -7
- package/src/__tests__/compaction.benchmark.test.ts +176 -0
- package/src/__tests__/computer-use-tools.test.ts +250 -0
- package/src/__tests__/config-schema.test.ts +299 -3
- package/src/__tests__/conflict-store.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +331 -0
- package/src/__tests__/conversation-store.test.ts +30 -32
- package/src/__tests__/credential-security-invariants.test.ts +4 -0
- package/src/__tests__/date-context.test.ts +373 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
- package/src/__tests__/followup-tools.test.ts +303 -0
- package/src/__tests__/handlers-twitter-config.test.ts +718 -0
- package/src/__tests__/intent-routing.test.ts +64 -57
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
- package/src/__tests__/ipc-snapshot.test.ts +62 -28
- package/src/__tests__/llm-usage-store.test.ts +3 -8
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
- package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
- package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
- package/src/__tests__/playbook-tools.test.ts +342 -0
- package/src/__tests__/profile-compiler.test.ts +2 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
- package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
- package/src/__tests__/recurrence-engine.test.ts +69 -0
- package/src/__tests__/recurrence-types.test.ts +71 -0
- package/src/__tests__/registry.test.ts +5 -3
- package/src/__tests__/relay-server.test.ts +633 -0
- package/src/__tests__/reminder-store.test.ts +6 -3
- package/src/__tests__/reminder.test.ts +43 -77
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +8 -4
- package/src/__tests__/run-orchestrator.test.ts +4 -4
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -6
- package/src/__tests__/runtime-runs-http.test.ts +4 -4
- package/src/__tests__/runtime-runs.test.ts +4 -4
- package/src/__tests__/schedule-store.test.ts +482 -0
- package/src/__tests__/schedule-tools.test.ts +700 -0
- package/src/__tests__/scheduler-recurrence.test.ts +329 -0
- package/src/__tests__/server-history-render.test.ts +14 -13
- package/src/__tests__/session-error.test.ts +28 -0
- package/src/__tests__/session-init.benchmark.test.ts +462 -0
- package/src/__tests__/session-queue.test.ts +71 -48
- package/src/__tests__/session-runtime-assembly.test.ts +161 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
- package/src/__tests__/signup-e2e.test.ts +2 -1
- package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
- package/src/__tests__/skill-script-runner.test.ts +159 -0
- package/src/__tests__/speaker-identification.test.ts +52 -0
- package/src/__tests__/subagent-manager-notify.test.ts +42 -10
- package/src/__tests__/subagent-tools.test.ts +141 -41
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-runner.test.ts +2 -1
- package/src/__tests__/task-scheduler.test.ts +2 -1
- package/src/__tests__/task-tools.test.ts +49 -56
- package/src/__tests__/tool-audit-listener.test.ts +1 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
- package/src/__tests__/tool-executor.test.ts +13 -17
- package/src/__tests__/turn-commit.test.ts +218 -3
- package/src/__tests__/twilio-provider.test.ts +143 -0
- package/src/__tests__/twilio-routes.test.ts +789 -0
- package/src/__tests__/twitter-auth-handler.test.ts +581 -0
- package/src/__tests__/view-image-tool.test.ts +217 -0
- package/src/__tests__/workspace-git-service.test.ts +186 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +13 -3
- package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
- package/src/bundler/app-bundler.ts +12 -8
- package/src/calls/call-bridge.ts +95 -0
- package/src/calls/call-constants.ts +43 -5
- package/src/calls/call-domain.ts +276 -0
- package/src/calls/call-orchestrator.ts +43 -17
- package/src/calls/call-recovery.ts +207 -0
- package/src/calls/call-state-machine.ts +68 -0
- package/src/calls/call-store.ts +192 -5
- package/src/calls/relay-server.ts +41 -4
- package/src/calls/speaker-identification.ts +213 -0
- package/src/calls/twilio-provider.ts +10 -6
- package/src/calls/twilio-routes.ts +90 -76
- package/src/calls/types.ts +1 -1
- package/src/cli/config-commands.ts +334 -0
- package/src/cli/core-commands.ts +776 -0
- package/src/cli/doordash.ts +251 -1
- package/src/cli/ipc-client.ts +82 -0
- package/src/cli/map.ts +246 -0
- package/src/cli/twitter.ts +575 -0
- package/src/cli.ts +7 -5
- package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
- package/src/commands/cc-command-registry.ts +209 -0
- package/src/config/bundled-skills/contacts/SKILL.md +39 -0
- package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
- package/src/config/bundled-skills/document/SKILL.md +18 -0
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
- package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
- package/src/config/bundled-skills/doordash/SKILL.md +82 -23
- package/src/config/bundled-skills/followups/SKILL.md +32 -0
- package/src/config/bundled-skills/followups/TOOLS.json +100 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +1 -23
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
- package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
- package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
- package/src/config/bundled-skills/reminder/SKILL.md +20 -0
- package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
- package/src/config/bundled-skills/schedule/SKILL.md +74 -0
- package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
- package/src/config/bundled-skills/subagent/SKILL.md +25 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
- package/src/config/bundled-skills/tasks/SKILL.md +28 -0
- package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
- package/src/config/bundled-skills/twitter/SKILL.md +134 -0
- package/src/config/bundled-skills/watcher/SKILL.md +27 -0
- package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
- package/src/config/defaults.ts +33 -0
- package/src/config/loader.ts +4 -1
- package/src/config/schema.ts +161 -1
- package/src/config/system-prompt.ts +61 -16
- package/src/config/templates/IDENTITY.md +7 -0
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +4 -4
- package/src/daemon/assistant-attachments.ts +10 -0
- package/src/daemon/classifier.ts +3 -1
- package/src/daemon/computer-use-session.ts +3 -1
- package/src/daemon/date-context.ts +136 -0
- package/src/daemon/handlers/apps.ts +16 -1
- package/src/daemon/handlers/browser.ts +54 -0
- package/src/daemon/handlers/computer-use.ts +7 -1
- package/src/daemon/handlers/config.ts +163 -5
- package/src/daemon/handlers/diagnostics.ts +5 -1
- package/src/daemon/handlers/documents.ts +18 -29
- package/src/daemon/handlers/home-base.ts +5 -1
- package/src/daemon/handlers/index.ts +40 -277
- package/src/daemon/handlers/misc.ts +9 -1
- package/src/daemon/handlers/publish.ts +6 -1
- package/src/daemon/handlers/sessions.ts +65 -12
- package/src/daemon/handlers/shared.ts +36 -1
- package/src/daemon/handlers/signing.ts +37 -0
- package/src/daemon/handlers/skills.ts +20 -6
- package/src/daemon/handlers/subagents.ts +8 -3
- package/src/daemon/handlers/twitter-auth.ts +169 -0
- package/src/daemon/handlers/work-items.ts +384 -68
- package/src/daemon/ipc-contract-inventory.json +28 -4
- package/src/daemon/ipc-contract.ts +133 -37
- package/src/daemon/ipc-protocol.ts +7 -2
- package/src/daemon/lifecycle.ts +21 -0
- package/src/daemon/main.ts +10 -4
- package/src/daemon/ride-shotgun-handler.ts +74 -10
- package/src/daemon/server.ts +143 -26
- package/src/daemon/session-agent-loop.ts +887 -0
- package/src/daemon/session-attachments.ts +28 -5
- package/src/daemon/session-error.ts +24 -3
- package/src/daemon/session-lifecycle.ts +147 -0
- package/src/daemon/session-media-retry.ts +147 -0
- package/src/daemon/session-messaging.ts +145 -0
- package/src/daemon/session-notifiers.ts +164 -0
- package/src/daemon/session-process.ts +2 -2
- package/src/daemon/session-queue-manager.ts +1 -0
- package/src/daemon/session-runtime-assembly.ts +52 -0
- package/src/daemon/session-skill-tools.ts +124 -5
- package/src/daemon/session-slash.ts +3 -0
- package/src/daemon/session-surfaces.ts +77 -2
- package/src/daemon/session-tool-setup.ts +216 -2
- package/src/daemon/session-usage.ts +0 -2
- package/src/daemon/session.ts +114 -1404
- package/src/daemon/video-thumbnail.ts +60 -0
- package/src/doordash/client.ts +121 -27
- package/src/doordash/queries.ts +1 -2
- package/src/export/formatter.ts +3 -1
- package/src/followups/followup-store.ts +4 -2
- package/src/followups/types.ts +6 -0
- package/src/hooks/templates.ts +1 -1
- package/src/index.ts +32 -1153
- package/src/memory/attachments-store.ts +28 -83
- package/src/memory/channel-delivery-store.ts +7 -21
- package/src/memory/clarification-resolver.ts +6 -5
- package/src/memory/contradiction-checker.ts +3 -2
- package/src/memory/conversation-key-store.ts +10 -29
- package/src/memory/conversation-store.ts +2 -1
- package/src/memory/db.ts +96 -2
- package/src/memory/entity-extractor.ts +6 -3
- package/src/memory/items-extractor.ts +5 -4
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/llm-usage-store.ts +1 -2
- package/src/memory/runs-store.ts +1 -2
- package/src/memory/schema.ts +23 -2
- package/src/messaging/style-analyzer.ts +3 -2
- package/src/messaging/thread-summarizer.ts +8 -12
- package/src/messaging/triage-engine.ts +4 -2
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/registry.ts +8 -0
- package/src/runtime/http-server.ts +108 -20
- package/src/runtime/routes/attachment-routes.ts +2 -3
- package/src/runtime/routes/call-routes.ts +140 -0
- package/src/runtime/routes/channel-routes.ts +5 -10
- package/src/runtime/routes/conversation-routes.ts +5 -5
- package/src/runtime/routes/run-routes.ts +2 -2
- package/src/runtime/run-orchestrator.ts +9 -3
- package/src/schedule/recurrence-engine.ts +138 -0
- package/src/schedule/recurrence-types.ts +67 -0
- package/src/schedule/schedule-store.ts +102 -57
- package/src/schedule/scheduler.ts +9 -6
- package/src/security/oauth2.ts +29 -4
- package/src/security/secret-allowlist.ts +46 -0
- package/src/skills/clawhub.ts +1 -1
- package/src/subagent/manager.ts +40 -8
- package/src/swarm/backend-claude-code.ts +64 -9
- package/src/swarm/worker-prompts.ts +2 -1
- package/src/tasks/SPEC.md +34 -28
- package/src/tasks/ephemeral-permissions.ts +16 -7
- package/src/tasks/task-compiler.ts +5 -4
- package/src/tasks/task-runner.ts +10 -5
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/tasks/tool-sanitizer.ts +36 -0
- package/src/tools/assets/search.ts +4 -4
- package/src/tools/browser/api-map.ts +220 -0
- package/src/tools/browser/auto-navigate.ts +270 -0
- package/src/tools/browser/browser-execution.ts +2 -1
- package/src/tools/browser/browser-manager.ts +2 -2
- package/src/tools/browser/network-recorder.ts +5 -4
- package/src/tools/browser/x-auto-navigate.ts +207 -0
- package/src/tools/calls/call-end.ts +17 -67
- package/src/tools/calls/call-start.ts +24 -85
- package/src/tools/calls/call-status.ts +35 -51
- package/src/tools/claude-code/claude-code.ts +77 -11
- package/src/tools/contacts/contact-merge.ts +46 -78
- package/src/tools/contacts/contact-search.ts +35 -79
- package/src/tools/contacts/contact-upsert.ts +35 -108
- package/src/tools/credentials/vault.ts +20 -4
- package/src/tools/document/document-tool.ts +71 -144
- package/src/tools/executor.ts +129 -10
- package/src/tools/followups/followup_create.ts +46 -88
- package/src/tools/followups/followup_list.ts +34 -74
- package/src/tools/followups/followup_resolve.ts +31 -66
- package/src/tools/host-terminal/cli-discover.ts +2 -1
- package/src/tools/host-terminal/host-shell.ts +10 -0
- package/src/tools/memory/handlers.ts +5 -4
- package/src/tools/network/__tests__/web-search.test.ts +427 -0
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
- package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
- package/src/tools/network/web-fetch.ts +18 -6
- package/src/tools/playbooks/index.ts +4 -5
- package/src/tools/playbooks/playbook-create.ts +3 -47
- package/src/tools/playbooks/playbook-delete.ts +1 -25
- package/src/tools/playbooks/playbook-list.ts +1 -28
- package/src/tools/playbooks/playbook-update.ts +3 -51
- package/src/tools/reminder/reminder.ts +5 -78
- package/src/tools/schedule/create.ts +69 -74
- package/src/tools/schedule/delete.ts +21 -47
- package/src/tools/schedule/list.ts +55 -74
- package/src/tools/schedule/update.ts +77 -84
- package/src/tools/subagent/abort.ts +29 -58
- package/src/tools/subagent/message.ts +30 -63
- package/src/tools/subagent/read.ts +53 -84
- package/src/tools/subagent/spawn.ts +43 -82
- package/src/tools/subagent/status.ts +42 -71
- package/src/tools/swarm/delegate.ts +2 -1
- package/src/tools/tasks/index.ts +8 -8
- package/src/tools/tasks/task-delete.ts +60 -88
- package/src/tools/tasks/task-list.ts +31 -52
- package/src/tools/tasks/task-run.ts +72 -108
- package/src/tools/tasks/task-save.ts +33 -65
- package/src/tools/tasks/work-item-enqueue.ts +183 -215
- package/src/tools/tasks/work-item-list.ts +33 -63
- package/src/tools/tasks/work-item-remove.ts +45 -97
- package/src/tools/tasks/work-item-update.ts +91 -163
- package/src/tools/terminal/backends/native.ts +3 -1
- package/src/tools/tool-manifest.ts +0 -62
- package/src/tools/types.ts +6 -0
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/tools/watch/screen-watch.ts +3 -1
- package/src/tools/watcher/create.ts +52 -98
- package/src/tools/watcher/delete.ts +20 -46
- package/src/tools/watcher/digest.ts +36 -70
- package/src/tools/watcher/list.ts +49 -79
- package/src/tools/watcher/update.ts +45 -91
- package/src/twitter/client.ts +690 -0
- package/src/twitter/session.ts +91 -0
- package/src/usage/types.ts +0 -1
- package/src/util/truncate.ts +6 -0
- package/src/watcher/providers/slack.ts +2 -1
- package/src/watcher/watcher-store.ts +3 -2
- package/src/work-items/work-item-store.ts +27 -2
- package/src/workspace/commit-message-enrichment-service.ts +31 -7
- package/src/workspace/git-service.ts +87 -22
- package/src/workspace/provider-commit-message-generator.ts +242 -0
- package/src/workspace/turn-commit.ts +62 -3
- package/src/tools/contacts/index.ts +0 -4
- package/src/tools/document/index.ts +0 -5
- package/src/tools/followups/index.ts +0 -3
- package/src/tools/subagent/index.ts +0 -5
- /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, afterAll, mock } from 'bun:test';
|
|
2
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
|
|
6
|
+
const testDir = mkdtempSync(join(tmpdir(), 'call-recovery-test-'));
|
|
7
|
+
|
|
8
|
+
mock.module('../util/platform.js', () => ({
|
|
9
|
+
getDataDir: () => testDir,
|
|
10
|
+
isMacOS: () => process.platform === 'darwin',
|
|
11
|
+
isLinux: () => process.platform === 'linux',
|
|
12
|
+
isWindows: () => process.platform === 'win32',
|
|
13
|
+
getSocketPath: () => join(testDir, 'test.sock'),
|
|
14
|
+
getPidPath: () => join(testDir, 'test.pid'),
|
|
15
|
+
getDbPath: () => join(testDir, 'test.db'),
|
|
16
|
+
getLogPath: () => join(testDir, 'test.log'),
|
|
17
|
+
ensureDataDir: () => {},
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
mock.module('../util/logger.js', () => ({
|
|
21
|
+
getLogger: () => new Proxy({} as Record<string, unknown>, {
|
|
22
|
+
get: () => () => {},
|
|
23
|
+
}),
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
import { initializeDb, getDb, resetDb } from '../memory/db.js';
|
|
27
|
+
import { conversations } from '../memory/schema.js';
|
|
28
|
+
import {
|
|
29
|
+
createCallSession,
|
|
30
|
+
updateCallSession,
|
|
31
|
+
getCallSession,
|
|
32
|
+
listRecoverableCalls,
|
|
33
|
+
createPendingQuestion,
|
|
34
|
+
getPendingQuestion,
|
|
35
|
+
} from '../calls/call-store.js';
|
|
36
|
+
import { reconcileCallsOnStartup, logDeadLetterEvent, NO_SID_GRACE_PERIOD_MS } from '../calls/call-recovery.js';
|
|
37
|
+
import type { VoiceProvider } from '../calls/voice-provider.js';
|
|
38
|
+
|
|
39
|
+
initializeDb();
|
|
40
|
+
|
|
41
|
+
afterAll(() => {
|
|
42
|
+
resetDb();
|
|
43
|
+
try { rmSync(testDir, { recursive: true }); } catch { /* best effort */ }
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/** Ensure a conversation row exists for the given ID so FK constraints pass. */
|
|
47
|
+
let ensuredConvIds = new Set<string>();
|
|
48
|
+
function ensureConversation(id: string): void {
|
|
49
|
+
if (ensuredConvIds.has(id)) return;
|
|
50
|
+
const db = getDb();
|
|
51
|
+
const now = Date.now();
|
|
52
|
+
db.insert(conversations).values({
|
|
53
|
+
id,
|
|
54
|
+
title: `Test conversation ${id}`,
|
|
55
|
+
createdAt: now,
|
|
56
|
+
updatedAt: now,
|
|
57
|
+
}).run();
|
|
58
|
+
ensuredConvIds.add(id);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resetTables() {
|
|
62
|
+
const db = getDb();
|
|
63
|
+
db.run('DELETE FROM call_pending_questions');
|
|
64
|
+
db.run('DELETE FROM call_events');
|
|
65
|
+
db.run('DELETE FROM call_sessions');
|
|
66
|
+
db.run('DELETE FROM conversations');
|
|
67
|
+
ensuredConvIds = new Set();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function createTestCallSession(opts: Parameters<typeof createCallSession>[0]) {
|
|
71
|
+
ensureConversation(opts.conversationId);
|
|
72
|
+
return createCallSession(opts);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Backdate a session's createdAt so it appears older than the grace period. */
|
|
76
|
+
function backdateSession(sessionId: string, ageMs: number): void {
|
|
77
|
+
const db = getDb();
|
|
78
|
+
const past = Date.now() - ageMs;
|
|
79
|
+
db.run(`UPDATE call_sessions SET created_at = ${past} WHERE id = '${sessionId}'`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Create a mock VoiceProvider that returns configurable statuses. */
|
|
83
|
+
function createMockProvider(statusMap: Record<string, string> = {}): VoiceProvider {
|
|
84
|
+
return {
|
|
85
|
+
name: 'mock-twilio',
|
|
86
|
+
initiateCall: async () => ({ callSid: 'mock-sid' }),
|
|
87
|
+
endCall: async () => {},
|
|
88
|
+
getCallStatus: async (callSid: string) => {
|
|
89
|
+
const status = statusMap[callSid];
|
|
90
|
+
if (status === undefined) {
|
|
91
|
+
throw new Error(`Unknown call SID: ${callSid}`);
|
|
92
|
+
}
|
|
93
|
+
return status;
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Silent logger for tests */
|
|
99
|
+
const silentLog = new Proxy({} as Record<string, unknown>, {
|
|
100
|
+
get: () => () => {},
|
|
101
|
+
}) as unknown as ReturnType<typeof import('../util/logger.js').getLogger>;
|
|
102
|
+
|
|
103
|
+
describe('listRecoverableCalls', () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
resetTables();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('returns sessions in non-terminal states', () => {
|
|
109
|
+
const s1 = createTestCallSession({
|
|
110
|
+
conversationId: 'conv-r1',
|
|
111
|
+
provider: 'twilio',
|
|
112
|
+
fromNumber: '+15551111111',
|
|
113
|
+
toNumber: '+15552222222',
|
|
114
|
+
});
|
|
115
|
+
// s1 is 'initiated' — should be recoverable
|
|
116
|
+
|
|
117
|
+
const s2 = createTestCallSession({
|
|
118
|
+
conversationId: 'conv-r2',
|
|
119
|
+
provider: 'twilio',
|
|
120
|
+
fromNumber: '+15551111111',
|
|
121
|
+
toNumber: '+15553333333',
|
|
122
|
+
});
|
|
123
|
+
updateCallSession(s2.id, { status: 'in_progress' });
|
|
124
|
+
// s2 is 'in_progress' — should be recoverable
|
|
125
|
+
|
|
126
|
+
const s3 = createTestCallSession({
|
|
127
|
+
conversationId: 'conv-r3',
|
|
128
|
+
provider: 'twilio',
|
|
129
|
+
fromNumber: '+15551111111',
|
|
130
|
+
toNumber: '+15554444444',
|
|
131
|
+
});
|
|
132
|
+
updateCallSession(s3.id, { status: 'ringing' });
|
|
133
|
+
// s3 is 'ringing' — should be recoverable
|
|
134
|
+
|
|
135
|
+
const results = listRecoverableCalls();
|
|
136
|
+
const ids = results.map(r => r.id);
|
|
137
|
+
|
|
138
|
+
expect(ids).toContain(s1.id);
|
|
139
|
+
expect(ids).toContain(s2.id);
|
|
140
|
+
expect(ids).toContain(s3.id);
|
|
141
|
+
expect(results).toHaveLength(3);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('does not include terminal calls (completed, failed, cancelled)', () => {
|
|
145
|
+
const completed = createTestCallSession({
|
|
146
|
+
conversationId: 'conv-t1',
|
|
147
|
+
provider: 'twilio',
|
|
148
|
+
fromNumber: '+15551111111',
|
|
149
|
+
toNumber: '+15552222222',
|
|
150
|
+
});
|
|
151
|
+
updateCallSession(completed.id, { status: 'completed' });
|
|
152
|
+
|
|
153
|
+
const failed = createTestCallSession({
|
|
154
|
+
conversationId: 'conv-t2',
|
|
155
|
+
provider: 'twilio',
|
|
156
|
+
fromNumber: '+15551111111',
|
|
157
|
+
toNumber: '+15553333333',
|
|
158
|
+
});
|
|
159
|
+
updateCallSession(failed.id, { status: 'failed' });
|
|
160
|
+
|
|
161
|
+
const cancelled = createTestCallSession({
|
|
162
|
+
conversationId: 'conv-t3',
|
|
163
|
+
provider: 'twilio',
|
|
164
|
+
fromNumber: '+15551111111',
|
|
165
|
+
toNumber: '+15554444444',
|
|
166
|
+
});
|
|
167
|
+
updateCallSession(cancelled.id, { status: 'cancelled' });
|
|
168
|
+
|
|
169
|
+
const results = listRecoverableCalls();
|
|
170
|
+
expect(results).toHaveLength(0);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('returns empty array when no calls exist', () => {
|
|
174
|
+
const results = listRecoverableCalls();
|
|
175
|
+
expect(results).toHaveLength(0);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('includes waiting_on_user status', () => {
|
|
179
|
+
const session = createTestCallSession({
|
|
180
|
+
conversationId: 'conv-w1',
|
|
181
|
+
provider: 'twilio',
|
|
182
|
+
fromNumber: '+15551111111',
|
|
183
|
+
toNumber: '+15552222222',
|
|
184
|
+
});
|
|
185
|
+
updateCallSession(session.id, { status: 'in_progress' });
|
|
186
|
+
updateCallSession(session.id, { status: 'waiting_on_user' });
|
|
187
|
+
|
|
188
|
+
const results = listRecoverableCalls();
|
|
189
|
+
expect(results).toHaveLength(1);
|
|
190
|
+
expect(results[0].id).toBe(session.id);
|
|
191
|
+
expect(results[0].status).toBe('waiting_on_user');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('reconcileCallsOnStartup', () => {
|
|
196
|
+
beforeEach(() => {
|
|
197
|
+
resetTables();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('does nothing when no recoverable calls exist', async () => {
|
|
201
|
+
const provider = createMockProvider();
|
|
202
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
203
|
+
// Should complete without error
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test('fails stale no-SID sessions past grace period', async () => {
|
|
207
|
+
const session = createTestCallSession({
|
|
208
|
+
conversationId: 'conv-nosid',
|
|
209
|
+
provider: 'twilio',
|
|
210
|
+
fromNumber: '+15551111111',
|
|
211
|
+
toNumber: '+15552222222',
|
|
212
|
+
});
|
|
213
|
+
// Backdate session so it exceeds the grace period
|
|
214
|
+
backdateSession(session.id, NO_SID_GRACE_PERIOD_MS + 10_000);
|
|
215
|
+
|
|
216
|
+
const provider = createMockProvider();
|
|
217
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
218
|
+
|
|
219
|
+
const updated = getCallSession(session.id);
|
|
220
|
+
expect(updated).not.toBeNull();
|
|
221
|
+
// Should be failed — orphan session past grace period
|
|
222
|
+
expect(updated!.status).toBe('failed');
|
|
223
|
+
expect(updated!.endedAt).not.toBeNull();
|
|
224
|
+
expect(updated!.lastError).toContain('grace period expired');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test('expires pending questions when stale no-SID session is failed', async () => {
|
|
228
|
+
const session = createTestCallSession({
|
|
229
|
+
conversationId: 'conv-nosid-pq',
|
|
230
|
+
provider: 'twilio',
|
|
231
|
+
fromNumber: '+15551111111',
|
|
232
|
+
toNumber: '+15552222222',
|
|
233
|
+
});
|
|
234
|
+
// Backdate session so it exceeds the grace period
|
|
235
|
+
backdateSession(session.id, NO_SID_GRACE_PERIOD_MS + 10_000);
|
|
236
|
+
|
|
237
|
+
// Create a pending question
|
|
238
|
+
createPendingQuestion(session.id, 'Are you still there?');
|
|
239
|
+
const pendingBefore = getPendingQuestion(session.id);
|
|
240
|
+
expect(pendingBefore).not.toBeNull();
|
|
241
|
+
expect(pendingBefore!.status).toBe('pending');
|
|
242
|
+
|
|
243
|
+
const provider = createMockProvider();
|
|
244
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
245
|
+
|
|
246
|
+
// Pending question should be expired along with the session
|
|
247
|
+
const pendingAfter = getPendingQuestion(session.id);
|
|
248
|
+
expect(pendingAfter).toBeNull();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test('skips recent no-SID sessions within grace period', async () => {
|
|
252
|
+
const session = createTestCallSession({
|
|
253
|
+
conversationId: 'conv-nosid-recent',
|
|
254
|
+
provider: 'twilio',
|
|
255
|
+
fromNumber: '+15551111111',
|
|
256
|
+
toNumber: '+15552222222',
|
|
257
|
+
});
|
|
258
|
+
// Session was just created (createdAt ~ Date.now()), well within grace period
|
|
259
|
+
|
|
260
|
+
const provider = createMockProvider();
|
|
261
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
262
|
+
|
|
263
|
+
const updated = getCallSession(session.id);
|
|
264
|
+
expect(updated).not.toBeNull();
|
|
265
|
+
// Should NOT be failed — still in its original non-terminal state
|
|
266
|
+
expect(updated!.status).toBe('initiated');
|
|
267
|
+
expect(updated!.endedAt).toBeNull();
|
|
268
|
+
expect(updated!.lastError).toContain('awaiting webhook');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test('transitions to completed when provider says call completed', async () => {
|
|
272
|
+
const session = createTestCallSession({
|
|
273
|
+
conversationId: 'conv-comp',
|
|
274
|
+
provider: 'twilio',
|
|
275
|
+
fromNumber: '+15551111111',
|
|
276
|
+
toNumber: '+15552222222',
|
|
277
|
+
});
|
|
278
|
+
updateCallSession(session.id, {
|
|
279
|
+
providerCallSid: 'CA_completed_123',
|
|
280
|
+
status: 'in_progress',
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const provider = createMockProvider({ 'CA_completed_123': 'completed' });
|
|
284
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
285
|
+
|
|
286
|
+
const updated = getCallSession(session.id);
|
|
287
|
+
expect(updated).not.toBeNull();
|
|
288
|
+
expect(updated!.status).toBe('completed');
|
|
289
|
+
expect(updated!.endedAt).not.toBeNull();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test('transitions to failed when provider says call failed', async () => {
|
|
293
|
+
const session = createTestCallSession({
|
|
294
|
+
conversationId: 'conv-fail',
|
|
295
|
+
provider: 'twilio',
|
|
296
|
+
fromNumber: '+15551111111',
|
|
297
|
+
toNumber: '+15552222222',
|
|
298
|
+
});
|
|
299
|
+
updateCallSession(session.id, {
|
|
300
|
+
providerCallSid: 'CA_failed_123',
|
|
301
|
+
status: 'ringing',
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
const provider = createMockProvider({ 'CA_failed_123': 'failed' });
|
|
305
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
306
|
+
|
|
307
|
+
const updated = getCallSession(session.id);
|
|
308
|
+
expect(updated).not.toBeNull();
|
|
309
|
+
expect(updated!.status).toBe('failed');
|
|
310
|
+
expect(updated!.endedAt).not.toBeNull();
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test('leaves call active when provider says call is still in-progress', async () => {
|
|
314
|
+
const session = createTestCallSession({
|
|
315
|
+
conversationId: 'conv-active',
|
|
316
|
+
provider: 'twilio',
|
|
317
|
+
fromNumber: '+15551111111',
|
|
318
|
+
toNumber: '+15552222222',
|
|
319
|
+
});
|
|
320
|
+
updateCallSession(session.id, {
|
|
321
|
+
providerCallSid: 'CA_active_123',
|
|
322
|
+
status: 'in_progress',
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const provider = createMockProvider({ 'CA_active_123': 'in-progress' });
|
|
326
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
327
|
+
|
|
328
|
+
const updated = getCallSession(session.id);
|
|
329
|
+
expect(updated).not.toBeNull();
|
|
330
|
+
expect(updated!.status).toBe('in_progress');
|
|
331
|
+
expect(updated!.endedAt).toBeNull();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
test('leaves call active when provider says call is ringing', async () => {
|
|
335
|
+
const session = createTestCallSession({
|
|
336
|
+
conversationId: 'conv-ring',
|
|
337
|
+
provider: 'twilio',
|
|
338
|
+
fromNumber: '+15551111111',
|
|
339
|
+
toNumber: '+15552222222',
|
|
340
|
+
});
|
|
341
|
+
updateCallSession(session.id, {
|
|
342
|
+
providerCallSid: 'CA_ringing_123',
|
|
343
|
+
status: 'ringing',
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const provider = createMockProvider({ 'CA_ringing_123': 'ringing' });
|
|
347
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
348
|
+
|
|
349
|
+
const updated = getCallSession(session.id);
|
|
350
|
+
expect(updated).not.toBeNull();
|
|
351
|
+
expect(updated!.status).toBe('ringing');
|
|
352
|
+
expect(updated!.endedAt).toBeNull();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test('expires pending questions when call transitions to terminal state', async () => {
|
|
356
|
+
const session = createTestCallSession({
|
|
357
|
+
conversationId: 'conv-expire',
|
|
358
|
+
provider: 'twilio',
|
|
359
|
+
fromNumber: '+15551111111',
|
|
360
|
+
toNumber: '+15552222222',
|
|
361
|
+
});
|
|
362
|
+
updateCallSession(session.id, {
|
|
363
|
+
providerCallSid: 'CA_expire_123',
|
|
364
|
+
status: 'in_progress',
|
|
365
|
+
});
|
|
366
|
+
updateCallSession(session.id, { status: 'waiting_on_user' });
|
|
367
|
+
|
|
368
|
+
// Create a pending question
|
|
369
|
+
createPendingQuestion(session.id, 'What is your name?');
|
|
370
|
+
|
|
371
|
+
// Verify the question is pending
|
|
372
|
+
const pendingBefore = getPendingQuestion(session.id);
|
|
373
|
+
expect(pendingBefore).not.toBeNull();
|
|
374
|
+
expect(pendingBefore!.status).toBe('pending');
|
|
375
|
+
|
|
376
|
+
const provider = createMockProvider({ 'CA_expire_123': 'completed' });
|
|
377
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
378
|
+
|
|
379
|
+
// Pending question should be expired
|
|
380
|
+
const pendingAfter = getPendingQuestion(session.id);
|
|
381
|
+
expect(pendingAfter).toBeNull();
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test('does not expire pending questions when call stays active', async () => {
|
|
385
|
+
const session = createTestCallSession({
|
|
386
|
+
conversationId: 'conv-keep',
|
|
387
|
+
provider: 'twilio',
|
|
388
|
+
fromNumber: '+15551111111',
|
|
389
|
+
toNumber: '+15552222222',
|
|
390
|
+
});
|
|
391
|
+
updateCallSession(session.id, {
|
|
392
|
+
providerCallSid: 'CA_keep_123',
|
|
393
|
+
status: 'in_progress',
|
|
394
|
+
});
|
|
395
|
+
updateCallSession(session.id, { status: 'waiting_on_user' });
|
|
396
|
+
|
|
397
|
+
createPendingQuestion(session.id, 'Still waiting?');
|
|
398
|
+
|
|
399
|
+
const provider = createMockProvider({ 'CA_keep_123': 'in-progress' });
|
|
400
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
401
|
+
|
|
402
|
+
// The pending question should still be there
|
|
403
|
+
const pendingAfter = getPendingQuestion(session.id);
|
|
404
|
+
expect(pendingAfter).not.toBeNull();
|
|
405
|
+
expect(pendingAfter!.status).toBe('pending');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
test('fails call when provider status fetch throws', async () => {
|
|
409
|
+
const session = createTestCallSession({
|
|
410
|
+
conversationId: 'conv-err',
|
|
411
|
+
provider: 'twilio',
|
|
412
|
+
fromNumber: '+15551111111',
|
|
413
|
+
toNumber: '+15552222222',
|
|
414
|
+
});
|
|
415
|
+
updateCallSession(session.id, {
|
|
416
|
+
providerCallSid: 'CA_error_123',
|
|
417
|
+
status: 'in_progress',
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// Provider will throw for unknown SIDs
|
|
421
|
+
const provider = createMockProvider({});
|
|
422
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
423
|
+
|
|
424
|
+
const updated = getCallSession(session.id);
|
|
425
|
+
expect(updated).not.toBeNull();
|
|
426
|
+
expect(updated!.status).toBe('failed');
|
|
427
|
+
expect(updated!.lastError).toContain('Recovery: failed to fetch provider status');
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
test('fails call when provider returns unrecognised status', async () => {
|
|
431
|
+
const session = createTestCallSession({
|
|
432
|
+
conversationId: 'conv-unk',
|
|
433
|
+
provider: 'twilio',
|
|
434
|
+
fromNumber: '+15551111111',
|
|
435
|
+
toNumber: '+15552222222',
|
|
436
|
+
});
|
|
437
|
+
updateCallSession(session.id, {
|
|
438
|
+
providerCallSid: 'CA_unknown_123',
|
|
439
|
+
status: 'in_progress',
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
const provider = createMockProvider({ 'CA_unknown_123': 'some-unknown-status' });
|
|
443
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
444
|
+
|
|
445
|
+
const updated = getCallSession(session.id);
|
|
446
|
+
expect(updated).not.toBeNull();
|
|
447
|
+
expect(updated!.status).toBe('failed');
|
|
448
|
+
expect(updated!.lastError).toContain("unrecognised provider status 'some-unknown-status'");
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test('handles mixed recoverable calls correctly', async () => {
|
|
452
|
+
// Call 1: no SID, stale — should be failed (orphan past grace period)
|
|
453
|
+
const noSid = createTestCallSession({
|
|
454
|
+
conversationId: 'conv-mix1',
|
|
455
|
+
provider: 'twilio',
|
|
456
|
+
fromNumber: '+15551111111',
|
|
457
|
+
toNumber: '+15552222222',
|
|
458
|
+
});
|
|
459
|
+
backdateSession(noSid.id, NO_SID_GRACE_PERIOD_MS + 10_000);
|
|
460
|
+
|
|
461
|
+
// Call 2: provider says completed — should complete
|
|
462
|
+
const completed = createTestCallSession({
|
|
463
|
+
conversationId: 'conv-mix2',
|
|
464
|
+
provider: 'twilio',
|
|
465
|
+
fromNumber: '+15551111111',
|
|
466
|
+
toNumber: '+15553333333',
|
|
467
|
+
});
|
|
468
|
+
updateCallSession(completed.id, {
|
|
469
|
+
providerCallSid: 'CA_mix_completed',
|
|
470
|
+
status: 'in_progress',
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// Call 3: provider says still active — should stay
|
|
474
|
+
const active = createTestCallSession({
|
|
475
|
+
conversationId: 'conv-mix3',
|
|
476
|
+
provider: 'twilio',
|
|
477
|
+
fromNumber: '+15551111111',
|
|
478
|
+
toNumber: '+15554444444',
|
|
479
|
+
});
|
|
480
|
+
updateCallSession(active.id, {
|
|
481
|
+
providerCallSid: 'CA_mix_active',
|
|
482
|
+
status: 'ringing',
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
const provider = createMockProvider({
|
|
486
|
+
'CA_mix_completed': 'completed',
|
|
487
|
+
'CA_mix_active': 'ringing',
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
await reconcileCallsOnStartup(provider, silentLog);
|
|
491
|
+
|
|
492
|
+
// No-SID session failed — orphan past grace period
|
|
493
|
+
const updatedNoSid = getCallSession(noSid.id);
|
|
494
|
+
expect(updatedNoSid!.status).toBe('failed');
|
|
495
|
+
expect(updatedNoSid!.endedAt).not.toBeNull();
|
|
496
|
+
expect(updatedNoSid!.lastError).toContain('grace period expired');
|
|
497
|
+
|
|
498
|
+
const updatedCompleted = getCallSession(completed.id);
|
|
499
|
+
expect(updatedCompleted!.status).toBe('completed');
|
|
500
|
+
|
|
501
|
+
const updatedActive = getCallSession(active.id);
|
|
502
|
+
expect(updatedActive!.status).toBe('ringing');
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
describe('logDeadLetterEvent', () => {
|
|
507
|
+
test('does not throw when called with a payload', () => {
|
|
508
|
+
expect(() => {
|
|
509
|
+
logDeadLetterEvent('test reason', { foo: 'bar' }, silentLog);
|
|
510
|
+
}).not.toThrow();
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
test('does not throw when called with null payload', () => {
|
|
514
|
+
expect(() => {
|
|
515
|
+
logDeadLetterEvent('null payload', null, silentLog);
|
|
516
|
+
}).not.toThrow();
|
|
517
|
+
});
|
|
518
|
+
});
|