@vellumai/assistant 0.12.1 → 0.12.2-staging.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/AGENTS.md +4 -0
- package/ARCHITECTURE.md +20 -21
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +13 -8
- package/node_modules/@vellumai/slack-text/src/label-resolution-entities.test.ts +95 -0
- package/openapi.yaml +360 -51
- package/package.json +3 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/anthropic-provider.test.ts +0 -63
- package/src/__tests__/app-compiler.test.ts +6 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
- package/src/__tests__/app-dir-path-guard.test.ts +1 -3
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
- package/src/__tests__/assistant-event-hub.test.ts +44 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +19 -7
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +28 -29
- package/src/__tests__/config-watcher.test.ts +23 -8
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +26 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
- package/src/__tests__/conversation-queue.test.ts +48 -207
- package/src/__tests__/conversation-retry-discard.test.ts +54 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +28 -0
- package/src/__tests__/conversation-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-point-at-capability.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +250 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/cu-unified-flow.test.ts +14 -4
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/heartbeat-service.test.ts +56 -40
- package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
- package/src/__tests__/host-bash-proxy.test.ts +26 -45
- package/src/__tests__/host-browser-proxy.test.ts +6 -17
- package/src/__tests__/host-cu-proxy.test.ts +596 -0
- package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
- package/src/__tests__/host-file-proxy.test.ts +11 -23
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
- package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
- package/src/__tests__/llm-catalog-parity.test.ts +25 -0
- package/src/__tests__/mcp-auth-routes.test.ts +6 -9
- package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
- package/src/__tests__/mcp-health-check.test.ts +8 -11
- package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +355 -548
- package/src/__tests__/model-intents.test.ts +3 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
- package/src/__tests__/oauth-commands-routes.test.ts +168 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +22 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-provider.test.ts +1 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +8 -16
- package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
- package/src/__tests__/qdrant-manager.test.ts +132 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/secret-routes-acp-guard.test.ts +59 -1
- package/src/__tests__/service-account-token.test.ts +247 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +70 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/ui-channel-variants.test.ts +1 -56
- package/src/__tests__/unicode.test.ts +13 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
- package/src/__tests__/workspace-git-service.test.ts +26 -0
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +257 -6
- package/src/acp/__tests__/acp-credentials.test.ts +13 -0
- package/src/acp/__tests__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/claude-token-refresh.test.ts +257 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +60 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/acp-claude-oauth.ts +328 -14
- package/src/acp/acp-credentials.ts +19 -0
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/claude-token-refresh.ts +150 -0
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/prepare-agent-env.ts +21 -6
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/agent/loop.ts +1 -0
- package/src/api/events/acp-session-model-update.test.ts +88 -0
- package/src/api/events/acp-session-model-update.ts +46 -0
- package/src/api/events/app-files-changed.ts +4 -3
- package/src/api/events/notification-intent.ts +2 -0
- package/src/api/events/user-message-echo.ts +7 -1
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +1 -1
- package/src/apps/resolve-app.ts +81 -0
- package/src/apps/source-fingerprint.ts +266 -0
- package/src/avatar/identity-avatar.ts +7 -2
- package/src/bundler/app-compiler.ts +15 -0
- package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
- package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
- package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
- package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
- package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
- package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
- package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
- package/src/calls/__tests__/voice-control-protocol.test.ts +120 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +56 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +155 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +92 -72
- package/src/calls/voice-triage-escalate.ts +178 -59
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/oauth/status.ts +5 -0
- package/src/cli/commands/roadmap.help.ts +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +29 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
- package/src/config/bundled-skills/schedule/SKILL.md +3 -4
- package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +33 -13
- package/src/config/loader.ts +2 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +18 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/credential-health/credential-health-service.ts +11 -17
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
- package/src/daemon/app-change-notify.ts +45 -0
- package/src/daemon/config-watcher.ts +13 -194
- package/src/daemon/conversation-error.ts +3 -2
- package/src/daemon/conversation-media-retry.ts +2 -1
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-runtime-assembly.ts +20 -7
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +21 -10
- package/src/daemon/conversation-tool-setup.ts +45 -59
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/dictation-profile-store.ts +2 -1
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +6 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-cu-proxy.ts +224 -19
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-proxy-preactivation.ts +2 -1
- package/src/daemon/host-transfer-proxy.ts +14 -18
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/reaction-history-render.ts +2 -1
- package/src/daemon/shutdown-handlers.ts +1 -9
- package/src/daemon/skill-memory-refresh.ts +64 -0
- package/src/daemon/tool-side-effects.ts +7 -18
- package/src/desktop/__tests__/fake-desktop.ts +122 -0
- package/src/desktop/desktop-chrome-policy.test.ts +79 -0
- package/src/desktop/desktop-chrome-policy.ts +47 -0
- package/src/desktop/desktop-chrome-session.ts +37 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +308 -0
- package/src/desktop/desktop-feature.test.ts +18 -0
- package/src/desktop/desktop-feature.ts +19 -0
- package/src/desktop/desktop-panel-config.test.ts +135 -0
- package/src/desktop/desktop-panel-config.ts +149 -0
- package/src/desktop/desktop-session-manager.test.ts +730 -0
- package/src/desktop/desktop-session-manager.ts +850 -0
- package/src/desktop/desktop-stream-bridge.test.ts +395 -0
- package/src/desktop/desktop-stream-bridge.ts +214 -0
- package/src/desktop/desktop-wallpaper.test.ts +191 -0
- package/src/desktop/desktop-wallpaper.ts +113 -0
- package/src/desktop/desktop-window-drag.ts +177 -0
- package/src/desktop/desktop-window-manager-config.test.ts +230 -0
- package/src/desktop/desktop-window-manager-config.ts +238 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/heartbeat/heartbeat-service.ts +21 -3
- package/src/home/__tests__/feed-writer.test.ts +22 -0
- package/src/home/feed-writer.ts +11 -2
- package/src/hooks/types.ts +33 -0
- package/src/i18n/AGENTS.md +22 -0
- package/src/i18n/__tests__/i18n.test.ts +108 -0
- package/src/i18n/index.ts +16 -0
- package/src/i18n/locales.ts +93 -0
- package/src/i18n/messages.ts +61 -0
- package/src/i18n/title.ts +25 -0
- package/src/inbound/platform-callback-registration.ts +4 -5
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +121 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +8 -7
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +94 -15
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/protocol.test.ts +39 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/__tests__/session-controls.test.ts +79 -0
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +297 -699
- package/src/live-voice/protocol.ts +60 -2
- package/src/live-voice/session-controls.ts +111 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +149 -0
- package/src/oauth/byo-connection.test.ts +105 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +100 -0
- package/src/oauth/connection-resolver.ts +120 -3
- package/src/oauth/provider-serializer.ts +9 -0
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +314 -27
- package/src/outbound-proxy/certs.ts +3 -5
- package/src/permissions/checker.test.ts +11 -6
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +71 -63
- package/src/persistence/conversation-lineage.ts +12 -4
- package/src/persistence/conversation-queries.ts +2 -2
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/embeddings/qdrant-manager.ts +163 -18
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-cursor.ts +78 -0
- package/src/persistence/message-reads.ts +30 -0
- package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
- package/src/persistence/schema/memory-core.ts +5 -0
- package/src/platform/client.test.ts +4 -2
- package/src/platform/client.ts +2 -10
- package/src/plugin-api/constants.ts +2 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +2 -0
- package/src/plugins/defaults/index.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
- package/src/plugins/defaults/memory/context-search/format.ts +3 -2
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
- package/src/plugins/defaults/memory/hooks/init.ts +10 -0
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
- package/src/plugins/defaults/memory/host-utils.ts +10 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
- package/src/plugins/defaults/memory/startup.ts +28 -2
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
- package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
- package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
- package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
- package/src/plugins/defaults/memory/v3/card.ts +3 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
- package/src/plugins/defaults/memory/v3/sections.ts +9 -3
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
- package/src/plugins/defaults/memory/worker.ts +6 -0
- package/src/plugins/mcp-servers.ts +15 -75
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/__tests__/retry-callsite.test.ts +41 -0
- package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
- package/src/providers/anthropic/client.ts +0 -47
- package/src/providers/gemini/client.ts +9 -23
- package/src/providers/gemini-thought-signature.test.ts +63 -0
- package/src/providers/gemini-thought-signature.ts +44 -0
- package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/endpoint-probe.ts +10 -1
- package/src/providers/inference/resolve-auth.ts +22 -4
- package/src/providers/inference/service-account-token.ts +248 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/model-intents.ts +10 -5
- package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
- package/src/providers/openai/chat-completions-provider.ts +212 -79
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/providers/opencode/client.test.ts +73 -4
- package/src/providers/opencode/client.ts +60 -3
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/outbound-request-sanitize.ts +96 -0
- package/src/providers/retry.ts +30 -19
- package/src/providers/unparseable-tool-args.ts +5 -1
- package/src/runtime/AGENTS.md +3 -1
- package/src/runtime/__tests__/channel-send.test.ts +443 -0
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
- package/src/runtime/__tests__/host-observe.test.ts +40 -1
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
- package/src/runtime/agent-wake.ts +2 -1
- package/src/runtime/assistant-event-hub.ts +21 -3
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/host-observe.ts +11 -1
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +16 -5
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +275 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-claude-auth-routes.ts +11 -3
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +90 -2
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +20 -14
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +61 -4
- package/src/runtime/routes/events-routes.ts +4 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -0
- package/src/runtime/routes/index.ts +4 -2
- package/src/runtime/routes/log-export-routes.ts +2 -0
- package/src/runtime/routes/mcp-auth-routes.ts +39 -47
- package/src/runtime/routes/migration-routes.ts +6 -20
- package/src/runtime/routes/oauth-commands-routes.ts +50 -0
- package/src/runtime/routes/oauth-providers.ts +7 -0
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/routes/workspace-routes.test.ts +55 -26
- package/src/runtime/routes/workspace-routes.ts +46 -63
- package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
- package/src/runtime/routes/workspace-tree-walk.ts +240 -0
- package/src/runtime/routes/workspace-utils.ts +17 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +16 -3
- package/src/runtime/sync/resource-sync-events.ts +2 -1
- package/src/schedule/run-script.ts +2 -1
- package/src/schedule/schedule-store.ts +9 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
- package/src/security/ces-http-record-backend.ts +120 -0
- package/src/security/ces-rpc-record-backend.ts +7 -0
- package/src/security/untrusted-content.ts +3 -1
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
- package/src/skills/workspace-skill-md-signature.ts +50 -0
- package/src/subagent/consult-context.ts +12 -25
- package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
- package/src/tools/acp/list-agents.test.ts +3 -1
- package/src/tools/acp/spawn.test.ts +146 -11
- package/src/tools/acp/spawn.ts +21 -3
- package/src/tools/acp/status.test.ts +94 -0
- package/src/tools/acp/status.ts +40 -3
- package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
- package/src/tools/browser/network-recorder.ts +2 -1
- package/src/tools/capability-offer.test.ts +22 -2
- package/src/tools/capability-offer.ts +16 -1
- package/src/tools/computer-use/definitions.ts +121 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/filesystem/search.ts +2 -1
- package/src/tools/host-filesystem/edit.test.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +2 -1
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +2 -1
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +16 -0
- package/src/tools/host-terminal/host-shell.ts +4 -20
- package/src/tools/network/web-search.ts +6 -1
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/skills/scaffold-managed.ts +61 -3
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/ui-surface/channel-variants.ts +10 -59
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/types/host-capabilities.ts +5 -3
- package/src/util/__tests__/language-subtag.test.ts +23 -1
- package/src/util/ca-bundle.ts +13 -0
- package/src/util/language-subtag.ts +16 -0
- package/src/util/platform.ts +8 -0
- package/src/util/unicode.ts +15 -1
- package/src/watch/watch-retro.ts +6 -8
- package/src/watch/watch-timeline.ts +2 -2
- package/src/workflows/run-manager.ts +2 -1
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +6 -55
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/app-source-watcher.test.ts +0 -218
- package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
- package/src/__tests__/speaker-identification.test.ts +0 -56
- package/src/calls/speaker-identification.ts +0 -233
- package/src/daemon/app-source-watcher.ts +0 -218
- package/src/messaging/providers/whatsapp/client.ts +0 -29
- package/src/runtime/routes/debug-bash-routes.ts +0 -173
- package/src/util/fs-watcher-error.ts +0 -36
- /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "../config/schemas/services.js";
|
|
7
7
|
import { VellumPlatformClient } from "../platform/client.js";
|
|
8
8
|
import { getLogger } from "../util/logger.js";
|
|
9
|
-
import { BYOOAuthConnection } from "./byo-connection.js";
|
|
9
|
+
import { BYOOAuthConnection, type BYOTokenHeader } from "./byo-connection.js";
|
|
10
10
|
import type { OAuthConnection } from "./connection.js";
|
|
11
11
|
import { getConnectionAccessTokenResult } from "./credential-token-resolver.js";
|
|
12
12
|
import { syncManualTokenConnection } from "./manual-token-connection.js";
|
|
@@ -129,7 +129,10 @@ export async function resolveOAuthConnectionWithMeta(
|
|
|
129
129
|
accountInfo: resolution.accountLabel ?? account ?? null,
|
|
130
130
|
client,
|
|
131
131
|
connectionId: resolution.id,
|
|
132
|
-
|
|
132
|
+
// A templated base URL (`https://{tenant_host}`, `.../{realm_id}`) is
|
|
133
|
+
// filled in by the platform from what it pinned to the connection;
|
|
134
|
+
// sent as-is it would fail the proxy's allowlist and shadow that.
|
|
135
|
+
baseUrl: platformProxyBaseUrl(providerRow?.baseUrl),
|
|
133
136
|
});
|
|
134
137
|
return {
|
|
135
138
|
connection,
|
|
@@ -215,15 +218,126 @@ export async function resolveOAuthConnectionWithMeta(
|
|
|
215
218
|
);
|
|
216
219
|
}
|
|
217
220
|
|
|
221
|
+
const effectiveBaseUrl = resolveEffectiveBaseUrl(
|
|
222
|
+
conn.provider,
|
|
223
|
+
baseUrl,
|
|
224
|
+
conn.metadata,
|
|
225
|
+
);
|
|
218
226
|
const connection = new BYOOAuthConnection({
|
|
219
227
|
id: conn.id,
|
|
220
228
|
provider: conn.provider,
|
|
221
|
-
baseUrl:
|
|
229
|
+
baseUrl: effectiveBaseUrl,
|
|
222
230
|
accountInfo: conn.accountInfo,
|
|
231
|
+
tokenHeader: resolveTokenHeader(
|
|
232
|
+
providerRow?.injectionTemplates,
|
|
233
|
+
effectiveBaseUrl,
|
|
234
|
+
),
|
|
223
235
|
});
|
|
224
236
|
return { connection, ambiguous, allAccounts };
|
|
225
237
|
}
|
|
226
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Pick the header a provider expects its access token in from the seed's
|
|
241
|
+
* header-type injection templates.
|
|
242
|
+
*
|
|
243
|
+
* Prefers the template whose `hostPattern` matches the base URL's host
|
|
244
|
+
* (`*.myshopify.com` style globs included), then falls back to the first
|
|
245
|
+
* header template. Returns `null` when the provider declares none, which
|
|
246
|
+
* leaves `BYOOAuthConnection` on its `Authorization: Bearer` default.
|
|
247
|
+
*
|
|
248
|
+
* Shopify is why this exists: its Admin API reads `X-Shopify-Access-Token`
|
|
249
|
+
* and ignores `Authorization`, so a Bearer header reaches the shop as an
|
|
250
|
+
* unauthenticated request and comes back 401.
|
|
251
|
+
*/
|
|
252
|
+
export function resolveTokenHeader(
|
|
253
|
+
rawTemplates: string | null | undefined,
|
|
254
|
+
baseUrl: string,
|
|
255
|
+
): BYOTokenHeader | null {
|
|
256
|
+
if (!rawTemplates) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
let parsed: unknown;
|
|
260
|
+
try {
|
|
261
|
+
parsed = JSON.parse(rawTemplates);
|
|
262
|
+
} catch {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
if (!Array.isArray(parsed)) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const headerTemplates = parsed.filter(
|
|
270
|
+
(
|
|
271
|
+
t,
|
|
272
|
+
): t is {
|
|
273
|
+
hostPattern?: unknown;
|
|
274
|
+
headerName: string;
|
|
275
|
+
valuePrefix?: unknown;
|
|
276
|
+
} =>
|
|
277
|
+
typeof t === "object" &&
|
|
278
|
+
t !== null &&
|
|
279
|
+
(t as { injectionType?: unknown }).injectionType === "header" &&
|
|
280
|
+
typeof (t as { headerName?: unknown }).headerName === "string" &&
|
|
281
|
+
(t as { headerName: string }).headerName.trim() !== "",
|
|
282
|
+
);
|
|
283
|
+
if (headerTemplates.length === 0) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
let host = "";
|
|
288
|
+
try {
|
|
289
|
+
host = new URL(baseUrl).hostname.toLowerCase();
|
|
290
|
+
} catch {
|
|
291
|
+
// Templated or malformed base URLs (e.g. a still-unfilled
|
|
292
|
+
// `https://{tenant_host}`) cannot be matched by host; fall through to
|
|
293
|
+
// the first header template.
|
|
294
|
+
}
|
|
295
|
+
const matching =
|
|
296
|
+
host === ""
|
|
297
|
+
? undefined
|
|
298
|
+
: headerTemplates.find(
|
|
299
|
+
(t) =>
|
|
300
|
+
typeof t.hostPattern === "string" &&
|
|
301
|
+
hostMatchesPattern(host, t.hostPattern),
|
|
302
|
+
);
|
|
303
|
+
const chosen = matching ?? headerTemplates[0];
|
|
304
|
+
return {
|
|
305
|
+
name: chosen.headerName.trim(),
|
|
306
|
+
valuePrefix:
|
|
307
|
+
typeof chosen.valuePrefix === "string" ? chosen.valuePrefix : "",
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function hostMatchesPattern(host: string, pattern: string): boolean {
|
|
312
|
+
const p = pattern.trim().toLowerCase();
|
|
313
|
+
if (p === "") {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
if (p.startsWith("*.")) {
|
|
317
|
+
const suffix = p.slice(1); // ".myshopify.com"
|
|
318
|
+
return host.endsWith(suffix) && host.length > suffix.length;
|
|
319
|
+
}
|
|
320
|
+
return host === p;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* The base URL a managed connection sends to the platform proxy, or
|
|
325
|
+
* `undefined` to let the proxy use the provider's configured default.
|
|
326
|
+
*
|
|
327
|
+
* Per-tenant and per-realm providers seed a template the platform fills from
|
|
328
|
+
* the connection (`{tenant_host}`, `{realm_id}`). Forwarding the unfilled
|
|
329
|
+
* template would fail the proxy's allowlist check, so those fall through to
|
|
330
|
+
* the platform's own default.
|
|
331
|
+
*/
|
|
332
|
+
export function platformProxyBaseUrl(
|
|
333
|
+
seedBaseUrl: string | null | undefined,
|
|
334
|
+
): string | undefined {
|
|
335
|
+
if (!seedBaseUrl || /\{[a-z_]+\}/.test(seedBaseUrl)) {
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
return seedBaseUrl;
|
|
339
|
+
}
|
|
340
|
+
|
|
227
341
|
/**
|
|
228
342
|
* Resolve the effective API base URL for a connection, preferring per-tenant
|
|
229
343
|
* values stored on the connection's `metadata` over the provider's static
|
|
@@ -301,6 +415,9 @@ interface PlatformConnectionEntry {
|
|
|
301
415
|
/** Scopes the platform actually granted this connection. May be absent for
|
|
302
416
|
* older connections or providers that don't report scopes. */
|
|
303
417
|
scopes_granted?: string[] | null;
|
|
418
|
+
/** Provider-supplied values the connection is scoped by (QuickBooks'
|
|
419
|
+
* `realm_id`). Absent from older platforms; empty for most providers. */
|
|
420
|
+
provider_params?: Record<string, string> | null;
|
|
304
421
|
}
|
|
305
422
|
|
|
306
423
|
interface PlatformConnectionResolution {
|
|
@@ -20,6 +20,8 @@ export type SerializedProvider = ReturnType<typeof serializeProvider> &
|
|
|
20
20
|
|
|
21
21
|
import { isChannelBotProvider } from "@vellumai/service-contracts/channels";
|
|
22
22
|
|
|
23
|
+
import { PROVIDER_SEED_DATA } from "./seed-providers.js";
|
|
24
|
+
|
|
23
25
|
/**
|
|
24
26
|
* Lightweight summary projection of an OAuth provider, suitable for API
|
|
25
27
|
* list responses where full detail is not needed. All keys are snake_case
|
|
@@ -36,6 +38,12 @@ export interface SerializedProviderSummary {
|
|
|
36
38
|
supports_managed_mode: boolean;
|
|
37
39
|
managed_service_is_paid: boolean;
|
|
38
40
|
feature_flag: string | null;
|
|
41
|
+
/**
|
|
42
|
+
* Per-tenant providers only (Shopify): what a client must collect before
|
|
43
|
+
* starting a managed connect, since the provider's OAuth endpoints live on
|
|
44
|
+
* the customer's own host. `null` for providers with one global host.
|
|
45
|
+
*/
|
|
46
|
+
tenant_host: { pattern: string; label: string; placeholder: string } | null;
|
|
39
47
|
/**
|
|
40
48
|
* Which sense of "connected" this provider represents: `assistant` for a bot
|
|
41
49
|
* credential people reach the assistant through, `user` for a grant letting
|
|
@@ -164,6 +172,7 @@ export function serializeProviderSummary(
|
|
|
164
172
|
supports_managed_mode: !!row.managedServiceConfigKey,
|
|
165
173
|
managed_service_is_paid: !!row.managedServiceIsPaid,
|
|
166
174
|
feature_flag: row.featureFlag ?? null,
|
|
175
|
+
tenant_host: PROVIDER_SEED_DATA[row.provider]?.tenantHost ?? null,
|
|
167
176
|
acts_as: isChannelBotProvider(row.provider) ? "assistant" : "user",
|
|
168
177
|
};
|
|
169
178
|
}
|
package/src/oauth/scope-utils.ts
CHANGED
|
@@ -72,6 +72,30 @@ export function expectedScopesForStoredToken(
|
|
|
72
72
|
return parsed.length > 0 ? parsed : defaultScopes;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* The required scopes a stored grant lacks. Requirements come from the request
|
|
77
|
+
* that produced the stored token ({@link expectedScopesForStoredToken}), so a
|
|
78
|
+
* provider's bot-only scopes are never demanded of a user token. An empty
|
|
79
|
+
* requirement or an unrecorded grant reports nothing, because unknown scope
|
|
80
|
+
* data must never read as a failure.
|
|
81
|
+
*/
|
|
82
|
+
export function missingScopesForStoredToken(
|
|
83
|
+
defaultScopes: string[],
|
|
84
|
+
authorizeParams: Record<string, string> | undefined,
|
|
85
|
+
scopeSeparator: string | undefined,
|
|
86
|
+
grantedScopes: string[],
|
|
87
|
+
): string[] {
|
|
88
|
+
const expected = expectedScopesForStoredToken(
|
|
89
|
+
defaultScopes,
|
|
90
|
+
authorizeParams,
|
|
91
|
+
scopeSeparator,
|
|
92
|
+
);
|
|
93
|
+
if (expected.length === 0 || grantedScopes.length === 0) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
return scopeDifference(expected, grantedScopes);
|
|
97
|
+
}
|
|
98
|
+
|
|
75
99
|
const GMAIL_FULL_ACCESS_SCOPE = "https://mail.google.com/";
|
|
76
100
|
const GMAIL_READONLY_SCOPE = "https://www.googleapis.com/auth/gmail.readonly";
|
|
77
101
|
|
|
@@ -9,6 +9,30 @@ import { migrateProviderBaseUrl, seedProviders } from "./oauth-store.js";
|
|
|
9
9
|
*/
|
|
10
10
|
const STALE_GOOGLE_BASE_URL = "https://gmail.googleapis.com/gmail/v1/users/me";
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* The hosts a Slack credential may be sent to, shared by the person-identity
|
|
14
|
+
* `slack` provider and the `slack_channel` bot: both read messages, and a file
|
|
15
|
+
* shared in a message is fetched from the file object's `url_private`,
|
|
16
|
+
* `url_private_download`, or `thumb_*` URL on `files.slack.com` with the same
|
|
17
|
+
* Bearer token as the Web API. Slack documents that one file host by name.
|
|
18
|
+
*/
|
|
19
|
+
const SLACK_PROVIDER_INJECTION_TEMPLATES: NonNullable<
|
|
20
|
+
(typeof PROVIDER_SEED_DATA)[string]["injectionTemplates"]
|
|
21
|
+
> = [
|
|
22
|
+
{
|
|
23
|
+
hostPattern: "slack.com",
|
|
24
|
+
injectionType: "header",
|
|
25
|
+
headerName: "Authorization",
|
|
26
|
+
valuePrefix: "Bearer ",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
hostPattern: "files.slack.com",
|
|
30
|
+
injectionType: "header",
|
|
31
|
+
headerName: "Authorization",
|
|
32
|
+
valuePrefix: "Bearer ",
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
12
36
|
/**
|
|
13
37
|
* Protocol-level seed data for each well-known OAuth provider.
|
|
14
38
|
*
|
|
@@ -66,6 +90,13 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
66
90
|
}>;
|
|
67
91
|
appType?: string;
|
|
68
92
|
setupNotes?: string[];
|
|
93
|
+
/**
|
|
94
|
+
* Per-tenant providers only: the host the user supplies at connect time,
|
|
95
|
+
* which the platform substitutes into `{tenant_host}` URL placeholders.
|
|
96
|
+
* `pattern` mirrors the platform registry's validation so clients can
|
|
97
|
+
* reject a malformed host before the request leaves the browser.
|
|
98
|
+
*/
|
|
99
|
+
tenantHost?: { pattern: string; label: string; placeholder: string };
|
|
69
100
|
identityUrl?: string;
|
|
70
101
|
identityMethod?: string;
|
|
71
102
|
identityHeaders?: Record<string, string>;
|
|
@@ -183,14 +214,13 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
183
214
|
clientIdPlaceholder: null,
|
|
184
215
|
logoUrl:
|
|
185
216
|
"https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/slack/default.svg",
|
|
186
|
-
// Sent as the bot `scope` parameter
|
|
187
|
-
// `authed_user` token and stores `authed_user.scope` as
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
// `
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
// channel-readiness-service.ts.
|
|
217
|
+
// Sent as the bot `scope` parameter on the same authorize request. This
|
|
218
|
+
// flow persists the `authed_user` token and stores `authed_user.scope` as
|
|
219
|
+
// `grantedScopes`; credential health measures that grant against
|
|
220
|
+
// `user_scope` below, never against this list, so a scope the stored
|
|
221
|
+
// token needs belongs in `user_scope`. The wider bot set belongs to Socket
|
|
222
|
+
// Mode installs, which verify the live `x-oauth-scopes` header against
|
|
223
|
+
// SLACK_REQUIRED_BOT_SCOPES in channel-readiness-service.ts.
|
|
194
224
|
defaultScopes: [
|
|
195
225
|
"channels:join",
|
|
196
226
|
"channels:read",
|
|
@@ -212,19 +242,17 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
212
242
|
// only credential this flow stores, so it acts as the installer for every
|
|
213
243
|
// call including `chat.postMessage`. The manifest's user list is read-only
|
|
214
244
|
// instead, since a Socket Mode install keeps a bot token beside it.
|
|
245
|
+
// `files:read` is what lets that token fetch a file shared in a message
|
|
246
|
+
// from files.slack.com. Credential health measures every stored grant
|
|
247
|
+
// against this list, so a scope added here reports each existing
|
|
248
|
+
// connection as `missing_scopes` until it reconnects: that is how a newly
|
|
249
|
+
// required scope reaches an install.
|
|
215
250
|
authorizeParams: {
|
|
216
251
|
user_scope:
|
|
217
|
-
"channels:read,channels:history,groups:read,groups:history,im:read,im:history,im:write,mpim:read,mpim:history,users:read,chat:write,search:read,reactions:write",
|
|
252
|
+
"channels:read,channels:history,groups:read,groups:history,im:read,im:history,im:write,mpim:read,mpim:history,users:read,chat:write,search:read,reactions:write,files:read",
|
|
218
253
|
},
|
|
219
254
|
loopbackPort: 17322,
|
|
220
|
-
injectionTemplates:
|
|
221
|
-
{
|
|
222
|
-
hostPattern: "slack.com",
|
|
223
|
-
injectionType: "header",
|
|
224
|
-
headerName: "Authorization",
|
|
225
|
-
valuePrefix: "Bearer ",
|
|
226
|
-
},
|
|
227
|
-
],
|
|
255
|
+
injectionTemplates: SLACK_PROVIDER_INJECTION_TEMPLATES,
|
|
228
256
|
appType: "Slack App",
|
|
229
257
|
identityUrl: "https://slack.com/api/auth.test",
|
|
230
258
|
identityOkField: "ok",
|
|
@@ -982,7 +1010,12 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
982
1010
|
// default, because Figma rejects the whole authorization request if the
|
|
983
1011
|
// app cannot grant a requested scope. `selections:read` is withheld for
|
|
984
1012
|
// that same reason: it is not offered in the app's OAuth scope list, so
|
|
985
|
-
// requesting it would fail the entire authorization.
|
|
1013
|
+
// requesting it would fail the entire authorization. `folders:read` is
|
|
1014
|
+
// withheld likewise: Figma documents it, but the app's scope picker only
|
|
1015
|
+
// offers `folder_metadata:read` under Folders. `file_code_connect:write`
|
|
1016
|
+
// is withheld because Figma only offers it to apps owned by an
|
|
1017
|
+
// Organization-plan team, which not every managed app is, and nothing
|
|
1018
|
+
// here uses Code Connect; it stays in availableScopes for BYO apps.
|
|
986
1019
|
defaultScopes: [
|
|
987
1020
|
"current_user:read",
|
|
988
1021
|
"file_content:read",
|
|
@@ -992,7 +1025,6 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
992
1025
|
"file_comments:write",
|
|
993
1026
|
"file_dev_resources:read",
|
|
994
1027
|
"file_dev_resources:write",
|
|
995
|
-
"folders:read",
|
|
996
1028
|
"folder_metadata:read",
|
|
997
1029
|
"library_content:read",
|
|
998
1030
|
"library_assets:read",
|
|
@@ -1032,6 +1064,10 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
1032
1064
|
scope: "file_dev_resources:write",
|
|
1033
1065
|
description: "Write dev resources to files",
|
|
1034
1066
|
},
|
|
1067
|
+
{
|
|
1068
|
+
scope: "file_code_connect:write",
|
|
1069
|
+
description: "Write and change component code (Code Connect)",
|
|
1070
|
+
},
|
|
1035
1071
|
{
|
|
1036
1072
|
scope: "folders:read",
|
|
1037
1073
|
description: "List folders and files in folders",
|
|
@@ -1194,14 +1230,7 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
1194
1230
|
logoUrl:
|
|
1195
1231
|
"https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/slack/default.svg",
|
|
1196
1232
|
defaultScopes: [],
|
|
1197
|
-
injectionTemplates:
|
|
1198
|
-
{
|
|
1199
|
-
hostPattern: "slack.com",
|
|
1200
|
-
injectionType: "header",
|
|
1201
|
-
headerName: "Authorization",
|
|
1202
|
-
valuePrefix: "Bearer ",
|
|
1203
|
-
},
|
|
1204
|
-
],
|
|
1233
|
+
injectionTemplates: SLACK_PROVIDER_INJECTION_TEMPLATES,
|
|
1205
1234
|
},
|
|
1206
1235
|
|
|
1207
1236
|
// The bot that sits in a server and talks to people there, which is a
|
|
@@ -1329,6 +1358,264 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
1329
1358
|
identityUrl: "https://api.link.com/userinfo",
|
|
1330
1359
|
identityResponsePaths: ["email", "phone"],
|
|
1331
1360
|
},
|
|
1361
|
+
shopify: {
|
|
1362
|
+
provider: "shopify",
|
|
1363
|
+
// Shopify is per-tenant: every OAuth endpoint lives on the merchant's own
|
|
1364
|
+
// myshopify.com domain, so these carry a {tenant_host} placeholder the
|
|
1365
|
+
// platform fills in from the shop domain the user supplies at connect
|
|
1366
|
+
// time. There is no global Shopify authorization host to point at.
|
|
1367
|
+
authorizeUrl: "https://{tenant_host}/admin/oauth/authorize",
|
|
1368
|
+
tokenExchangeUrl: "https://{tenant_host}/admin/oauth/access_token",
|
|
1369
|
+
// Requesting `expiring=1` at token exchange yields a short-lived access
|
|
1370
|
+
// token plus a refresh token, which is refreshed against the same
|
|
1371
|
+
// per-shop endpoint.
|
|
1372
|
+
refreshUrl: "https://{tenant_host}/admin/oauth/access_token",
|
|
1373
|
+
pingUrl: "https://{tenant_host}/admin/api/2026-07/shop.json",
|
|
1374
|
+
baseUrl: "https://{tenant_host}",
|
|
1375
|
+
displayLabel: "Shopify",
|
|
1376
|
+
description: "Products, orders, customers, and inventory",
|
|
1377
|
+
dashboardUrl: "https://shopify.dev/dashboard",
|
|
1378
|
+
clientIdPlaceholder: null,
|
|
1379
|
+
logoUrl: "https://cdn.simpleicons.org/shopify",
|
|
1380
|
+
// Shopify parses `scope` as a comma-separated list. A space-separated
|
|
1381
|
+
// list is read as one malformed scope and the request is rejected.
|
|
1382
|
+
scopeSeparator: ",",
|
|
1383
|
+
// Admin API scopes only: Storefront, Customer Account and Shop APIs are
|
|
1384
|
+
// buyer-facing surfaces an assistant has no use for. Every scope here is
|
|
1385
|
+
// grantable without Shopify approval -- the approval-gated ones
|
|
1386
|
+
// (read_all_orders, customer payment methods, subscription contracts,
|
|
1387
|
+
// dispute evidence) are deliberately absent, because Shopify rejects the
|
|
1388
|
+
// whole authorization request if the app cannot grant a requested scope.
|
|
1389
|
+
// A write_* grant implies its read_* counterpart, so the response may
|
|
1390
|
+
// name only the write scope.
|
|
1391
|
+
defaultScopes: [
|
|
1392
|
+
"read_products",
|
|
1393
|
+
"write_products",
|
|
1394
|
+
"read_orders",
|
|
1395
|
+
"write_orders",
|
|
1396
|
+
"read_draft_orders",
|
|
1397
|
+
"write_draft_orders",
|
|
1398
|
+
"read_customers",
|
|
1399
|
+
"write_customers",
|
|
1400
|
+
"read_inventory",
|
|
1401
|
+
"read_locations",
|
|
1402
|
+
"read_fulfillments",
|
|
1403
|
+
"read_discounts",
|
|
1404
|
+
"write_discounts",
|
|
1405
|
+
"read_price_rules",
|
|
1406
|
+
],
|
|
1407
|
+
availableScopes: [
|
|
1408
|
+
{
|
|
1409
|
+
scope: "read_products",
|
|
1410
|
+
description: "Read products, variants, and collections",
|
|
1411
|
+
},
|
|
1412
|
+
{
|
|
1413
|
+
scope: "write_products",
|
|
1414
|
+
description: "Create and update products, variants, and collections",
|
|
1415
|
+
},
|
|
1416
|
+
{
|
|
1417
|
+
scope: "read_orders",
|
|
1418
|
+
description: "Read orders, transactions, and abandoned checkouts",
|
|
1419
|
+
},
|
|
1420
|
+
{
|
|
1421
|
+
scope: "write_orders",
|
|
1422
|
+
description: "Create and update orders and fulfillments",
|
|
1423
|
+
},
|
|
1424
|
+
{ scope: "read_draft_orders", description: "Read draft orders" },
|
|
1425
|
+
{
|
|
1426
|
+
scope: "write_draft_orders",
|
|
1427
|
+
description: "Create and update draft orders",
|
|
1428
|
+
},
|
|
1429
|
+
{
|
|
1430
|
+
scope: "read_customers",
|
|
1431
|
+
description: "Read customers, segments, and companies",
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
scope: "write_customers",
|
|
1435
|
+
description: "Create and update customers and segments",
|
|
1436
|
+
},
|
|
1437
|
+
{
|
|
1438
|
+
scope: "read_inventory",
|
|
1439
|
+
description: "Read inventory levels and items",
|
|
1440
|
+
},
|
|
1441
|
+
{
|
|
1442
|
+
scope: "write_inventory",
|
|
1443
|
+
description: "Adjust inventory levels and items",
|
|
1444
|
+
},
|
|
1445
|
+
{ scope: "read_locations", description: "Read store locations" },
|
|
1446
|
+
{ scope: "read_fulfillments", description: "Read fulfillment services" },
|
|
1447
|
+
{
|
|
1448
|
+
scope: "write_fulfillments",
|
|
1449
|
+
description: "Create and update fulfillment services",
|
|
1450
|
+
},
|
|
1451
|
+
{ scope: "read_discounts", description: "Read discounts" },
|
|
1452
|
+
{ scope: "write_discounts", description: "Create and update discounts" },
|
|
1453
|
+
{ scope: "read_price_rules", description: "Read price rules" },
|
|
1454
|
+
{
|
|
1455
|
+
scope: "write_price_rules",
|
|
1456
|
+
description: "Create and update price rules",
|
|
1457
|
+
},
|
|
1458
|
+
{ scope: "read_files", description: "Read files uploaded to the store" },
|
|
1459
|
+
{ scope: "write_files", description: "Upload and update files" },
|
|
1460
|
+
{ scope: "read_gift_cards", description: "Read gift cards" },
|
|
1461
|
+
{
|
|
1462
|
+
scope: "write_gift_cards",
|
|
1463
|
+
description: "Create and update gift cards",
|
|
1464
|
+
},
|
|
1465
|
+
{ scope: "read_returns", description: "Read returns" },
|
|
1466
|
+
{ scope: "write_returns", description: "Create and update returns" },
|
|
1467
|
+
{ scope: "read_markets", description: "Read markets" },
|
|
1468
|
+
{ scope: "read_locales", description: "Read shop locales" },
|
|
1469
|
+
{
|
|
1470
|
+
scope: "read_shipping",
|
|
1471
|
+
description: "Read shipping and delivery carrier services",
|
|
1472
|
+
},
|
|
1473
|
+
{ scope: "read_analytics", description: "Read analytics and reports" },
|
|
1474
|
+
{
|
|
1475
|
+
scope: "read_marketing_events",
|
|
1476
|
+
description: "Read marketing events and activities",
|
|
1477
|
+
},
|
|
1478
|
+
{ scope: "read_order_edits", description: "Read order edits" },
|
|
1479
|
+
{
|
|
1480
|
+
scope: "write_order_edits",
|
|
1481
|
+
description: "Create and apply order edits",
|
|
1482
|
+
},
|
|
1483
|
+
{
|
|
1484
|
+
scope: "read_metaobjects",
|
|
1485
|
+
description: "Read metaobjects and their definitions",
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
scope: "write_metaobjects",
|
|
1489
|
+
description: "Create and update metaobjects",
|
|
1490
|
+
},
|
|
1491
|
+
{ scope: "read_translations", description: "Read translated content" },
|
|
1492
|
+
{
|
|
1493
|
+
scope: "read_shopify_payments_payouts",
|
|
1494
|
+
description: "Read Shopify Payments payouts and balance",
|
|
1495
|
+
},
|
|
1496
|
+
{
|
|
1497
|
+
scope: "read_shopify_payments_disputes",
|
|
1498
|
+
description: "Read Shopify Payments disputes",
|
|
1499
|
+
},
|
|
1500
|
+
],
|
|
1501
|
+
loopbackPort: 17341,
|
|
1502
|
+
managedServiceConfigKey: "shopify-oauth",
|
|
1503
|
+
// Mirrors `extra_config.tenant_host` in the platform provider registry.
|
|
1504
|
+
tenantHost: {
|
|
1505
|
+
pattern: "^[a-z0-9][a-z0-9-]*\\.myshopify\\.com$",
|
|
1506
|
+
label: "Shop domain",
|
|
1507
|
+
placeholder: "your-store.myshopify.com",
|
|
1508
|
+
},
|
|
1509
|
+
injectionTemplates: [
|
|
1510
|
+
{
|
|
1511
|
+
hostPattern: "*.myshopify.com",
|
|
1512
|
+
injectionType: "header",
|
|
1513
|
+
headerName: "X-Shopify-Access-Token",
|
|
1514
|
+
valuePrefix: "",
|
|
1515
|
+
},
|
|
1516
|
+
],
|
|
1517
|
+
appType: "App",
|
|
1518
|
+
setupNotes: [
|
|
1519
|
+
"Shopify OAuth is per-shop: the authorize, token and API endpoints all live on the merchant's own myshopify.com domain, so connecting requires the shop domain (for example your-store.myshopify.com) alongside the usual credentials.",
|
|
1520
|
+
"The Admin API authenticates with the X-Shopify-Access-Token header rather than an Authorization Bearer header.",
|
|
1521
|
+
],
|
|
1522
|
+
// The Admin API's shop endpoint nests its payload under "shop"; the
|
|
1523
|
+
// myshopify domain is the stable, human-recognisable handle.
|
|
1524
|
+
identityUrl: "https://{tenant_host}/admin/api/2026-07/shop.json",
|
|
1525
|
+
identityResponsePaths: ["shop.myshopify_domain", "shop.name"],
|
|
1526
|
+
// Gated like monday/figma/stripe-link: the platform side and the
|
|
1527
|
+
// shop-domain input in the clients land separately, and until both are
|
|
1528
|
+
// in place a visible Shopify tile would offer a connect flow that
|
|
1529
|
+
// cannot complete.
|
|
1530
|
+
featureFlag: "shopify-oauth",
|
|
1531
|
+
},
|
|
1532
|
+
|
|
1533
|
+
quickbooks: {
|
|
1534
|
+
provider: "quickbooks",
|
|
1535
|
+
authorizeUrl: "https://appcenter.intuit.com/connect/oauth2",
|
|
1536
|
+
tokenExchangeUrl:
|
|
1537
|
+
"https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
|
|
1538
|
+
// Access tokens live an hour; refresh tokens 100 days and are rotated on
|
|
1539
|
+
// every refresh, which the platform persists. Both token endpoints
|
|
1540
|
+
// authenticate the client with HTTP Basic.
|
|
1541
|
+
refreshUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
|
|
1542
|
+
tokenEndpointAuthMethod: "client_secret_basic",
|
|
1543
|
+
// No revokeUrl: Intuit's revocation endpoint wants a JSON body under HTTP
|
|
1544
|
+
// Basic client auth, and the daemon's revoke helper only posts an
|
|
1545
|
+
// unauthenticated form body, so a seeded URL would fail silently on every
|
|
1546
|
+
// your-own disconnect. The platform registry revokes managed tokens itself.
|
|
1547
|
+
// Every Accounting API path is scoped to the company (realm) the user
|
|
1548
|
+
// picked on Intuit's consent screen. The realm arrives only as the
|
|
1549
|
+
// callback's `realmId` query parameter; the platform captures it into the
|
|
1550
|
+
// connection's `provider_params` and fills the `{realm_id}` placeholder
|
|
1551
|
+
// server-side, so managed callers send paths relative to the company
|
|
1552
|
+
// (`/query`, `/customer/123`). Production and sandbox keys use different
|
|
1553
|
+
// hosts; the platform picks the host per environment.
|
|
1554
|
+
baseUrl: "https://quickbooks.api.intuit.com/v3/company/{realm_id}",
|
|
1555
|
+
// No pingUrl: the only company-independent probe would still need the
|
|
1556
|
+
// realm in its path, which the ping route cannot fill in (it sends the
|
|
1557
|
+
// URL's origin as a per-request base override, which would also pin a
|
|
1558
|
+
// managed sandbox connection to the production host).
|
|
1559
|
+
displayLabel: "QuickBooks",
|
|
1560
|
+
description: "Invoices, customers, vendors, and accounting data",
|
|
1561
|
+
dashboardUrl: "https://developer.intuit.com/app/developer/dashboard",
|
|
1562
|
+
clientIdPlaceholder: null,
|
|
1563
|
+
logoUrl: "https://cdn.simpleicons.org/quickbooks",
|
|
1564
|
+
// The Accounting scope covers the QuickBooks Online API. Payments is a
|
|
1565
|
+
// separate product the app must be enabled for, and the OpenID scopes
|
|
1566
|
+
// only add the signing-in user's profile, so none are on by default.
|
|
1567
|
+
defaultScopes: ["com.intuit.quickbooks.accounting"],
|
|
1568
|
+
availableScopes: [
|
|
1569
|
+
{
|
|
1570
|
+
scope: "com.intuit.quickbooks.accounting",
|
|
1571
|
+
description:
|
|
1572
|
+
"Read and write QuickBooks Online accounting data: customers, vendors, invoices, bills, payments, items, accounts, and reports",
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
scope: "com.intuit.quickbooks.payment",
|
|
1576
|
+
description:
|
|
1577
|
+
"QuickBooks Payments: charges, refunds, bank accounts, and cards (requires a Payments-enabled app)",
|
|
1578
|
+
},
|
|
1579
|
+
{ scope: "openid", description: "Sign in with Intuit (OpenID Connect)" },
|
|
1580
|
+
{ scope: "profile", description: "The signing-in user's name" },
|
|
1581
|
+
{ scope: "email", description: "The signing-in user's email address" },
|
|
1582
|
+
{ scope: "phone", description: "The signing-in user's phone number" },
|
|
1583
|
+
{ scope: "address", description: "The signing-in user's address" },
|
|
1584
|
+
],
|
|
1585
|
+
loopbackPort: 17342,
|
|
1586
|
+
managedServiceConfigKey: "quickbooks-oauth",
|
|
1587
|
+
injectionTemplates: [
|
|
1588
|
+
{
|
|
1589
|
+
hostPattern: "quickbooks.api.intuit.com",
|
|
1590
|
+
injectionType: "header",
|
|
1591
|
+
headerName: "Authorization",
|
|
1592
|
+
valuePrefix: "Bearer ",
|
|
1593
|
+
},
|
|
1594
|
+
{
|
|
1595
|
+
hostPattern: "sandbox-quickbooks.api.intuit.com",
|
|
1596
|
+
injectionType: "header",
|
|
1597
|
+
headerName: "Authorization",
|
|
1598
|
+
valuePrefix: "Bearer ",
|
|
1599
|
+
},
|
|
1600
|
+
],
|
|
1601
|
+
appType: "App",
|
|
1602
|
+
setupNotes: [
|
|
1603
|
+
"QuickBooks scopes every Accounting API call to the company (realm) chosen on Intuit's consent screen. Managed connections carry the realm as provider_params.realm_id and requests are sent relative to /v3/company/{realmId}.",
|
|
1604
|
+
"Intuit development keys only authorize sandbox companies, which live on sandbox-quickbooks.api.intuit.com; production keys use quickbooks.api.intuit.com.",
|
|
1605
|
+
"The Accounting API returns XML unless the request carries Accept: application/json.",
|
|
1606
|
+
],
|
|
1607
|
+
// CompanyInfo does not repeat the realm (its Id is always "1"); the
|
|
1608
|
+
// platform keys the connection on the captured realm and labels it with
|
|
1609
|
+
// the company name.
|
|
1610
|
+
identityUrl:
|
|
1611
|
+
"https://quickbooks.api.intuit.com/v3/company/{realm_id}/companyinfo/{realm_id}",
|
|
1612
|
+
identityHeaders: { Accept: "application/json" },
|
|
1613
|
+
identityResponsePaths: ["CompanyInfo.CompanyName", "CompanyInfo.LegalName"],
|
|
1614
|
+
// Gated like figma/shopify: the platform side lands separately, and until
|
|
1615
|
+
// the client ids are live a visible tile would offer a connect flow that
|
|
1616
|
+
// cannot complete.
|
|
1617
|
+
featureFlag: "quickbooks-oauth",
|
|
1618
|
+
},
|
|
1332
1619
|
};
|
|
1333
1620
|
|
|
1334
1621
|
export const SEEDED_PROVIDER_KEYS = new Set(Object.keys(PROVIDER_SEED_DATA));
|
|
@@ -2,6 +2,8 @@ import { X509Certificate } from "node:crypto";
|
|
|
2
2
|
import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
|
|
5
|
+
import { writeCombinedCABundle } from "../util/ca-bundle.js";
|
|
6
|
+
|
|
5
7
|
const CA_CERT_FILENAME = "ca.pem";
|
|
6
8
|
const CA_KEY_FILENAME = "ca-key.pem";
|
|
7
9
|
const COMBINED_CA_FILENAME = "combined-ca-bundle.pem";
|
|
@@ -263,11 +265,7 @@ export async function ensureCombinedCABundle(
|
|
|
263
265
|
}
|
|
264
266
|
|
|
265
267
|
try {
|
|
266
|
-
|
|
267
|
-
readFile(systemBundlePath, "utf-8"),
|
|
268
|
-
readFile(caCertPath, "utf-8"),
|
|
269
|
-
]);
|
|
270
|
-
await writeFile(combinedPath, systemCAs + "\n" + proxyCACert);
|
|
268
|
+
await writeCombinedCABundle(systemBundlePath, caCertPath, combinedPath);
|
|
271
269
|
return combinedPath;
|
|
272
270
|
} catch {
|
|
273
271
|
return null;
|