@agenticmail/enterprise 0.5.327 → 0.5.329
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/dist/agent-tools-F3CYENMK.js +13949 -0
- package/dist/browser-tool-P57PLVW2.js +4002 -0
- package/dist/chunk-3RI3AIJN.js +1519 -0
- package/dist/chunk-AD4DFKHR.js +4928 -0
- package/dist/chunk-UQXPVWXG.js +5101 -0
- package/dist/cli-agent-K6UFZRXC.js +2473 -0
- package/dist/cli-serve-4MT7RDEL.js +260 -0
- package/dist/cli.js +3 -3
- package/dist/dashboard/app.js +1 -1
- package/dist/dashboard/components/transport-encryption.js +0 -62
- package/dist/dashboard/pages/agent-detail/index.js +5 -2
- package/dist/dashboard/pages/agent-detail/manager.js +1 -1
- package/dist/dashboard/pages/agent-detail/overview.js +4 -2
- package/dist/dashboard/pages/agent-detail/tool-security.js +1 -1
- package/dist/dashboard/pages/domain-status.js +3 -6
- package/dist/dashboard/pages/memory-transfer.js +1 -1
- package/dist/dashboard/pages/messages.js +0 -1
- package/dist/dashboard/pages/roles.js +0 -2
- package/dist/dashboard/pages/workforce.js +0 -1
- package/dist/index.js +3 -3
- package/dist/runtime-L5ADJORP.js +45 -0
- package/dist/server-KSN56EZQ.js +28 -0
- package/dist/setup-UUNBBOQH.js +20 -0
- package/logs/cloudflared-error.log +42 -0
- package/logs/enterprise-out.log +6 -0
- package/package.json +1 -1
- package/src/admin/page-registry.ts +0 -290
- package/src/admin/routes.ts +0 -2968
- package/src/agent-tools/common.ts +0 -260
- package/src/agent-tools/index.ts +0 -542
- package/src/agent-tools/merge.ts +0 -62
- package/src/agent-tools/middleware.ts +0 -436
- package/src/agent-tools/schema/typebox.ts +0 -25
- package/src/agent-tools/security.ts +0 -352
- package/src/agent-tools/tool-resolver.ts +0 -1018
- package/src/agent-tools/tools/agenticmail.ts +0 -1017
- package/src/agent-tools/tools/bash.ts +0 -179
- package/src/agent-tools/tools/browser-tool.schema.ts +0 -112
- package/src/agent-tools/tools/browser-tool.ts +0 -388
- package/src/agent-tools/tools/browser.ts +0 -764
- package/src/agent-tools/tools/edit.ts +0 -100
- package/src/agent-tools/tools/enterprise-code-sandbox.ts +0 -395
- package/src/agent-tools/tools/enterprise-database.ts +0 -377
- package/src/agent-tools/tools/enterprise-diff.ts +0 -580
- package/src/agent-tools/tools/enterprise-documents.ts +0 -896
- package/src/agent-tools/tools/enterprise-http.ts +0 -485
- package/src/agent-tools/tools/enterprise-security-scan.ts +0 -528
- package/src/agent-tools/tools/enterprise-spreadsheet.ts +0 -825
- package/src/agent-tools/tools/glob.ts +0 -129
- package/src/agent-tools/tools/google/calendar.ts +0 -230
- package/src/agent-tools/tools/google/chat.ts +0 -725
- package/src/agent-tools/tools/google/contacts.ts +0 -209
- package/src/agent-tools/tools/google/docs.ts +0 -162
- package/src/agent-tools/tools/google/drive.ts +0 -392
- package/src/agent-tools/tools/google/forms.ts +0 -367
- package/src/agent-tools/tools/google/gmail.ts +0 -897
- package/src/agent-tools/tools/google/index.ts +0 -86
- package/src/agent-tools/tools/google/maps.ts +0 -543
- package/src/agent-tools/tools/google/meeting-voice.ts +0 -885
- package/src/agent-tools/tools/google/meetings.ts +0 -1094
- package/src/agent-tools/tools/google/sheets.ts +0 -215
- package/src/agent-tools/tools/google/slides.ts +0 -559
- package/src/agent-tools/tools/google/tasks.ts +0 -200
- package/src/agent-tools/tools/grep.ts +0 -178
- package/src/agent-tools/tools/integrations/_factory.ts +0 -102
- package/src/agent-tools/tools/integrations/activecampaign.ts +0 -14
- package/src/agent-tools/tools/integrations/adobe-sign.ts +0 -14
- package/src/agent-tools/tools/integrations/adp.ts +0 -14
- package/src/agent-tools/tools/integrations/airtable.ts +0 -14
- package/src/agent-tools/tools/integrations/apollo.ts +0 -14
- package/src/agent-tools/tools/integrations/asana.ts +0 -14
- package/src/agent-tools/tools/integrations/auth0.ts +0 -14
- package/src/agent-tools/tools/integrations/aws.ts +0 -14
- package/src/agent-tools/tools/integrations/azure-devops.ts +0 -14
- package/src/agent-tools/tools/integrations/bamboohr.ts +0 -14
- package/src/agent-tools/tools/integrations/basecamp.ts +0 -14
- package/src/agent-tools/tools/integrations/bigcommerce.ts +0 -14
- package/src/agent-tools/tools/integrations/bitbucket.ts +0 -14
- package/src/agent-tools/tools/integrations/box.ts +0 -14
- package/src/agent-tools/tools/integrations/brex.ts +0 -14
- package/src/agent-tools/tools/integrations/buffer.ts +0 -14
- package/src/agent-tools/tools/integrations/calendly.ts +0 -14
- package/src/agent-tools/tools/integrations/canva.ts +0 -14
- package/src/agent-tools/tools/integrations/chargebee.ts +0 -14
- package/src/agent-tools/tools/integrations/circleci.ts +0 -14
- package/src/agent-tools/tools/integrations/clickup.ts +0 -14
- package/src/agent-tools/tools/integrations/close.ts +0 -14
- package/src/agent-tools/tools/integrations/cloudflare.ts +0 -14
- package/src/agent-tools/tools/integrations/confluence.ts +0 -14
- package/src/agent-tools/tools/integrations/contentful.ts +0 -14
- package/src/agent-tools/tools/integrations/copper.ts +0 -14
- package/src/agent-tools/tools/integrations/crisp.ts +0 -14
- package/src/agent-tools/tools/integrations/crowdstrike.ts +0 -14
- package/src/agent-tools/tools/integrations/datadog.ts +0 -14
- package/src/agent-tools/tools/integrations/digitalocean.ts +0 -14
- package/src/agent-tools/tools/integrations/discord.ts +0 -14
- package/src/agent-tools/tools/integrations/docker.ts +0 -14
- package/src/agent-tools/tools/integrations/docusign.ts +0 -14
- package/src/agent-tools/tools/integrations/drift.ts +0 -14
- package/src/agent-tools/tools/integrations/dropbox.ts +0 -14
- package/src/agent-tools/tools/integrations/figma.ts +0 -14
- package/src/agent-tools/tools/integrations/firebase.ts +0 -14
- package/src/agent-tools/tools/integrations/flyio.ts +0 -14
- package/src/agent-tools/tools/integrations/freshbooks.ts +0 -14
- package/src/agent-tools/tools/integrations/freshdesk.ts +0 -14
- package/src/agent-tools/tools/integrations/freshsales.ts +0 -14
- package/src/agent-tools/tools/integrations/freshservice.ts +0 -14
- package/src/agent-tools/tools/integrations/front.ts +0 -14
- package/src/agent-tools/tools/integrations/github-actions.ts +0 -14
- package/src/agent-tools/tools/integrations/github.ts +0 -14
- package/src/agent-tools/tools/integrations/gitlab.ts +0 -14
- package/src/agent-tools/tools/integrations/gong.ts +0 -14
- package/src/agent-tools/tools/integrations/google-ads.ts +0 -14
- package/src/agent-tools/tools/integrations/google-analytics.ts +0 -14
- package/src/agent-tools/tools/integrations/google-cloud.ts +0 -14
- package/src/agent-tools/tools/integrations/gotomeeting.ts +0 -14
- package/src/agent-tools/tools/integrations/grafana.ts +0 -14
- package/src/agent-tools/tools/integrations/greenhouse.ts +0 -14
- package/src/agent-tools/tools/integrations/gusto.ts +0 -14
- package/src/agent-tools/tools/integrations/hashicorp-vault.ts +0 -14
- package/src/agent-tools/tools/integrations/heroku.ts +0 -14
- package/src/agent-tools/tools/integrations/hibob.ts +0 -14
- package/src/agent-tools/tools/integrations/hootsuite.ts +0 -14
- package/src/agent-tools/tools/integrations/hubspot.ts +0 -14
- package/src/agent-tools/tools/integrations/huggingface.ts +0 -14
- package/src/agent-tools/tools/integrations/index.ts +0 -474
- package/src/agent-tools/tools/integrations/intercom.ts +0 -14
- package/src/agent-tools/tools/integrations/jira.ts +0 -14
- package/src/agent-tools/tools/integrations/klaviyo.ts +0 -14
- package/src/agent-tools/tools/integrations/kubernetes.ts +0 -14
- package/src/agent-tools/tools/integrations/lattice.ts +0 -14
- package/src/agent-tools/tools/integrations/launchdarkly.ts +0 -14
- package/src/agent-tools/tools/integrations/lever.ts +0 -14
- package/src/agent-tools/tools/integrations/linear.ts +0 -14
- package/src/agent-tools/tools/integrations/linkedin.ts +0 -14
- package/src/agent-tools/tools/integrations/livechat.ts +0 -14
- package/src/agent-tools/tools/integrations/loom.ts +0 -14
- package/src/agent-tools/tools/integrations/mailchimp.ts +0 -14
- package/src/agent-tools/tools/integrations/mailgun.ts +0 -14
- package/src/agent-tools/tools/integrations/miro.ts +0 -14
- package/src/agent-tools/tools/integrations/mixpanel.ts +0 -14
- package/src/agent-tools/tools/integrations/monday.ts +0 -14
- package/src/agent-tools/tools/integrations/mongodb-atlas.ts +0 -14
- package/src/agent-tools/tools/integrations/neon.ts +0 -14
- package/src/agent-tools/tools/integrations/netlify.ts +0 -14
- package/src/agent-tools/tools/integrations/netsuite.ts +0 -14
- package/src/agent-tools/tools/integrations/newrelic.ts +0 -14
- package/src/agent-tools/tools/integrations/notion.ts +0 -14
- package/src/agent-tools/tools/integrations/okta.ts +0 -14
- package/src/agent-tools/tools/integrations/openai.ts +0 -14
- package/src/agent-tools/tools/integrations/opsgenie.ts +0 -14
- package/src/agent-tools/tools/integrations/outreach.ts +0 -14
- package/src/agent-tools/tools/integrations/paddle.ts +0 -14
- package/src/agent-tools/tools/integrations/pagerduty.ts +0 -14
- package/src/agent-tools/tools/integrations/pandadoc.ts +0 -14
- package/src/agent-tools/tools/integrations/paypal.ts +0 -14
- package/src/agent-tools/tools/integrations/personio.ts +0 -14
- package/src/agent-tools/tools/integrations/pinecone.ts +0 -14
- package/src/agent-tools/tools/integrations/pipedrive.ts +0 -14
- package/src/agent-tools/tools/integrations/plaid.ts +0 -14
- package/src/agent-tools/tools/integrations/postmark.ts +0 -14
- package/src/agent-tools/tools/integrations/power-automate.ts +0 -14
- package/src/agent-tools/tools/integrations/quickbooks.ts +0 -14
- package/src/agent-tools/tools/integrations/recurly.ts +0 -14
- package/src/agent-tools/tools/integrations/reddit.ts +0 -14
- package/src/agent-tools/tools/integrations/render.ts +0 -14
- package/src/agent-tools/tools/integrations/ringcentral.ts +0 -14
- package/src/agent-tools/tools/integrations/rippling.ts +0 -14
- package/src/agent-tools/tools/integrations/salesforce.ts +0 -14
- package/src/agent-tools/tools/integrations/salesloft.ts +0 -14
- package/src/agent-tools/tools/integrations/sanity.ts +0 -14
- package/src/agent-tools/tools/integrations/sap.ts +0 -14
- package/src/agent-tools/tools/integrations/segment.ts +0 -14
- package/src/agent-tools/tools/integrations/sendgrid.ts +0 -14
- package/src/agent-tools/tools/integrations/sentry.ts +0 -14
- package/src/agent-tools/tools/integrations/servicenow.ts +0 -14
- package/src/agent-tools/tools/integrations/shopify.ts +0 -14
- package/src/agent-tools/tools/integrations/shortcut.ts +0 -14
- package/src/agent-tools/tools/integrations/slack.ts +0 -14
- package/src/agent-tools/tools/integrations/smartsheet.ts +0 -14
- package/src/agent-tools/tools/integrations/snowflake.ts +0 -14
- package/src/agent-tools/tools/integrations/snyk.ts +0 -14
- package/src/agent-tools/tools/integrations/splunk.ts +0 -14
- package/src/agent-tools/tools/integrations/square.ts +0 -14
- package/src/agent-tools/tools/integrations/statuspage.ts +0 -14
- package/src/agent-tools/tools/integrations/stripe.ts +0 -14
- package/src/agent-tools/tools/integrations/supabase.ts +0 -14
- package/src/agent-tools/tools/integrations/teamwork.ts +0 -14
- package/src/agent-tools/tools/integrations/telegram.ts +0 -14
- package/src/agent-tools/tools/integrations/terraform.ts +0 -14
- package/src/agent-tools/tools/integrations/todoist.ts +0 -14
- package/src/agent-tools/tools/integrations/trello.ts +0 -14
- package/src/agent-tools/tools/integrations/twilio.ts +0 -14
- package/src/agent-tools/tools/integrations/twitter.ts +0 -14
- package/src/agent-tools/tools/integrations/vercel.ts +0 -14
- package/src/agent-tools/tools/integrations/weaviate.ts +0 -14
- package/src/agent-tools/tools/integrations/webex.ts +0 -14
- package/src/agent-tools/tools/integrations/webflow.ts +0 -14
- package/src/agent-tools/tools/integrations/whatsapp.ts +0 -14
- package/src/agent-tools/tools/integrations/whereby.ts +0 -14
- package/src/agent-tools/tools/integrations/woocommerce.ts +0 -14
- package/src/agent-tools/tools/integrations/wordpress.ts +0 -14
- package/src/agent-tools/tools/integrations/workday.ts +0 -14
- package/src/agent-tools/tools/integrations/wrike.ts +0 -14
- package/src/agent-tools/tools/integrations/xero.ts +0 -14
- package/src/agent-tools/tools/integrations/youtube.ts +0 -14
- package/src/agent-tools/tools/integrations/zendesk.ts +0 -14
- package/src/agent-tools/tools/integrations/zoho-crm.ts +0 -14
- package/src/agent-tools/tools/integrations/zoom.ts +0 -14
- package/src/agent-tools/tools/integrations/zuora.ts +0 -14
- package/src/agent-tools/tools/knowledge-search.ts +0 -318
- package/src/agent-tools/tools/local/coding.ts +0 -626
- package/src/agent-tools/tools/local/dependency-manager.ts +0 -647
- package/src/agent-tools/tools/local/file-edit.ts +0 -31
- package/src/agent-tools/tools/local/file-list.ts +0 -39
- package/src/agent-tools/tools/local/file-ops.ts +0 -48
- package/src/agent-tools/tools/local/file-read.ts +0 -39
- package/src/agent-tools/tools/local/file-search.ts +0 -46
- package/src/agent-tools/tools/local/file-write.ts +0 -28
- package/src/agent-tools/tools/local/filesystem.ts +0 -5
- package/src/agent-tools/tools/local/index.ts +0 -55
- package/src/agent-tools/tools/local/resolve-path.ts +0 -18
- package/src/agent-tools/tools/local/shell.ts +0 -277
- package/src/agent-tools/tools/local/system-info.ts +0 -29
- package/src/agent-tools/tools/management.ts +0 -425
- package/src/agent-tools/tools/mcp-bridge.ts +0 -142
- package/src/agent-tools/tools/mcp-server-tools.ts +0 -91
- package/src/agent-tools/tools/meeting-lifecycle.ts +0 -438
- package/src/agent-tools/tools/memory.ts +0 -509
- package/src/agent-tools/tools/messaging/index.ts +0 -6
- package/src/agent-tools/tools/messaging/telegram.ts +0 -167
- package/src/agent-tools/tools/messaging/whatsapp.ts +0 -651
- package/src/agent-tools/tools/microsoft/contacts.ts +0 -176
- package/src/agent-tools/tools/microsoft/excel-vba.ts +0 -331
- package/src/agent-tools/tools/microsoft/excel.ts +0 -261
- package/src/agent-tools/tools/microsoft/graph-api.ts +0 -161
- package/src/agent-tools/tools/microsoft/index.ts +0 -95
- package/src/agent-tools/tools/microsoft/onedrive.ts +0 -429
- package/src/agent-tools/tools/microsoft/onenote.ts +0 -186
- package/src/agent-tools/tools/microsoft/outlook-calendar.ts +0 -286
- package/src/agent-tools/tools/microsoft/outlook-mail.ts +0 -723
- package/src/agent-tools/tools/microsoft/planner.ts +0 -200
- package/src/agent-tools/tools/microsoft/powerbi.ts +0 -266
- package/src/agent-tools/tools/microsoft/powerpoint.ts +0 -186
- package/src/agent-tools/tools/microsoft/sharepoint.ts +0 -328
- package/src/agent-tools/tools/microsoft/teams.ts +0 -463
- package/src/agent-tools/tools/microsoft/todo.ts +0 -181
- package/src/agent-tools/tools/oauth-token-provider.ts +0 -101
- package/src/agent-tools/tools/read.ts +0 -160
- package/src/agent-tools/tools/visual-memory/capture.ts +0 -217
- package/src/agent-tools/tools/visual-memory/diff.ts +0 -283
- package/src/agent-tools/tools/visual-memory/index.ts +0 -698
- package/src/agent-tools/tools/visual-memory/phash.ts +0 -120
- package/src/agent-tools/tools/visual-memory/similarity.ts +0 -354
- package/src/agent-tools/tools/visual-memory/storage.ts +0 -534
- package/src/agent-tools/tools/visual-memory/types.ts +0 -100
- package/src/agent-tools/tools/web-fetch-utils.ts +0 -202
- package/src/agent-tools/tools/web-fetch.ts +0 -464
- package/src/agent-tools/tools/web-search.ts +0 -480
- package/src/agent-tools/tools/web-shared.ts +0 -232
- package/src/agent-tools/tools/write.ts +0 -68
- package/src/agent-tools/types.ts +0 -214
- package/src/agenticmail/index.ts +0 -34
- package/src/agenticmail/manager.ts +0 -253
- package/src/agenticmail/providers/google.ts +0 -391
- package/src/agenticmail/providers/imap.ts +0 -454
- package/src/agenticmail/providers/index.ts +0 -28
- package/src/agenticmail/providers/microsoft.ts +0 -260
- package/src/agenticmail/types.ts +0 -173
- package/src/auth/routes.ts +0 -1589
- package/src/browser/bridge-auth-registry.ts +0 -34
- package/src/browser/bridge-server.ts +0 -93
- package/src/browser/cdp.helpers.ts +0 -180
- package/src/browser/cdp.ts +0 -466
- package/src/browser/chrome.executables.ts +0 -625
- package/src/browser/chrome.profile-decoration.ts +0 -198
- package/src/browser/chrome.ts +0 -349
- package/src/browser/client-actions-core.ts +0 -259
- package/src/browser/client-actions-observe.ts +0 -184
- package/src/browser/client-actions-state.ts +0 -284
- package/src/browser/client-actions-types.ts +0 -16
- package/src/browser/client-actions-url.ts +0 -11
- package/src/browser/client-actions.ts +0 -4
- package/src/browser/client-fetch.ts +0 -253
- package/src/browser/client.ts +0 -337
- package/src/browser/config.ts +0 -301
- package/src/browser/constants.ts +0 -8
- package/src/browser/control-auth.ts +0 -94
- package/src/browser/control-service.ts +0 -81
- package/src/browser/csrf.ts +0 -87
- package/src/browser/enterprise-compat.ts +0 -562
- package/src/browser/extension-relay.ts +0 -834
- package/src/browser/http-auth.ts +0 -63
- package/src/browser/navigation-guard.ts +0 -50
- package/src/browser/paths.ts +0 -49
- package/src/browser/playwright.d.ts +0 -12
- package/src/browser/profiles-service.ts +0 -187
- package/src/browser/profiles.ts +0 -114
- package/src/browser/proxy-files.ts +0 -41
- package/src/browser/pw-ai-module.ts +0 -52
- package/src/browser/pw-ai-state.ts +0 -9
- package/src/browser/pw-ai.ts +0 -65
- package/src/browser/pw-role-snapshot.ts +0 -434
- package/src/browser/pw-session.ts +0 -810
- package/src/browser/pw-tools-core.activity.ts +0 -68
- package/src/browser/pw-tools-core.downloads.ts +0 -281
- package/src/browser/pw-tools-core.interactions.ts +0 -646
- package/src/browser/pw-tools-core.responses.ts +0 -124
- package/src/browser/pw-tools-core.shared.ts +0 -70
- package/src/browser/pw-tools-core.snapshot.ts +0 -213
- package/src/browser/pw-tools-core.state.ts +0 -209
- package/src/browser/pw-tools-core.storage.ts +0 -128
- package/src/browser/pw-tools-core.trace.ts +0 -37
- package/src/browser/pw-tools-core.ts +0 -8
- package/src/browser/resolved-config-refresh.ts +0 -59
- package/src/browser/routes/agent.act.shared.ts +0 -52
- package/src/browser/routes/agent.act.ts +0 -575
- package/src/browser/routes/agent.debug.ts +0 -149
- package/src/browser/routes/agent.shared.ts +0 -143
- package/src/browser/routes/agent.snapshot.ts +0 -333
- package/src/browser/routes/agent.storage.ts +0 -451
- package/src/browser/routes/agent.ts +0 -13
- package/src/browser/routes/basic.ts +0 -202
- package/src/browser/routes/dispatcher.ts +0 -126
- package/src/browser/routes/index.ts +0 -11
- package/src/browser/routes/path-output.ts +0 -1
- package/src/browser/routes/tabs.ts +0 -217
- package/src/browser/routes/types.ts +0 -26
- package/src/browser/routes/utils.ts +0 -73
- package/src/browser/screenshot.ts +0 -54
- package/src/browser/server-context.ts +0 -688
- package/src/browser/server-context.types.ts +0 -65
- package/src/browser/server-lifecycle.ts +0 -48
- package/src/browser/server-middleware.ts +0 -37
- package/src/browser/server.ts +0 -110
- package/src/browser/target-id.ts +0 -30
- package/src/browser/trash.ts +0 -21
- package/src/cli-agent.ts +0 -2452
- package/src/cli-reset-password.ts +0 -138
- package/src/cli-serve.ts +0 -314
- package/src/cli.ts +0 -103
- package/src/dashboard/app.js +0 -579
- package/src/dashboard/assets/brand-logos.js +0 -350
- package/src/dashboard/assets/icons/emoji-icons.js +0 -893
- package/src/dashboard/assets/logo.png +0 -0
- package/src/dashboard/assets/provider-logos.js +0 -139
- package/src/dashboard/components/error-boundary.js +0 -21
- package/src/dashboard/components/help-button.js +0 -65
- package/src/dashboard/components/icons.js +0 -64
- package/src/dashboard/components/knowledge-link.js +0 -79
- package/src/dashboard/components/modal.js +0 -125
- package/src/dashboard/components/org-switcher.js +0 -156
- package/src/dashboard/components/persona-fields.js +0 -460
- package/src/dashboard/components/settings-help.js +0 -193
- package/src/dashboard/components/tag-input.js +0 -96
- package/src/dashboard/components/timezones.js +0 -352
- package/src/dashboard/components/transport-encryption.js +0 -288
- package/src/dashboard/components/utils.js +0 -205
- package/src/dashboard/data/countries.js +0 -255
- package/src/dashboard/docs/activity.html +0 -253
- package/src/dashboard/docs/agent-activity.html +0 -199
- package/src/dashboard/docs/agent-autonomy.html +0 -161
- package/src/dashboard/docs/agent-budget.html +0 -190
- package/src/dashboard/docs/agent-channels.html +0 -189
- package/src/dashboard/docs/agent-communication.html +0 -171
- package/src/dashboard/docs/agent-configuration.html +0 -194
- package/src/dashboard/docs/agent-deployment.html +0 -323
- package/src/dashboard/docs/agent-email.html +0 -184
- package/src/dashboard/docs/agent-guardrails.html +0 -206
- package/src/dashboard/docs/agent-manager.html +0 -226
- package/src/dashboard/docs/agent-memory.html +0 -215
- package/src/dashboard/docs/agent-overview.html +0 -226
- package/src/dashboard/docs/agent-permissions.html +0 -305
- package/src/dashboard/docs/agent-personal.html +0 -155
- package/src/dashboard/docs/agent-security.html +0 -188
- package/src/dashboard/docs/agent-skills.html +0 -224
- package/src/dashboard/docs/agent-tool-security.html +0 -205
- package/src/dashboard/docs/agent-tools.html +0 -238
- package/src/dashboard/docs/agent-whatsapp.html +0 -210
- package/src/dashboard/docs/agent-workforce.html +0 -199
- package/src/dashboard/docs/agents.html +0 -258
- package/src/dashboard/docs/approvals.html +0 -200
- package/src/dashboard/docs/audit.html +0 -206
- package/src/dashboard/docs/browser-providers.html +0 -313
- package/src/dashboard/docs/cluster.html +0 -285
- package/src/dashboard/docs/community-skills.html +0 -253
- package/src/dashboard/docs/compliance.html +0 -221
- package/src/dashboard/docs/dashboard.html +0 -84
- package/src/dashboard/docs/database-access.html +0 -322
- package/src/dashboard/docs/dlp.html +0 -268
- package/src/dashboard/docs/docs-style.css +0 -26
- package/src/dashboard/docs/domain-status.html +0 -294
- package/src/dashboard/docs/guardrails.html +0 -265
- package/src/dashboard/docs/journal.html +0 -197
- package/src/dashboard/docs/knowledge-contributions.html +0 -286
- package/src/dashboard/docs/knowledge.html +0 -268
- package/src/dashboard/docs/memory-transfer.html +0 -311
- package/src/dashboard/docs/messages.html +0 -217
- package/src/dashboard/docs/multi-tenant.html +0 -311
- package/src/dashboard/docs/org-chart.html +0 -239
- package/src/dashboard/docs/organizations.html +0 -182
- package/src/dashboard/docs/roles.html +0 -195
- package/src/dashboard/docs/settings-network.html +0 -321
- package/src/dashboard/docs/settings-security.html +0 -347
- package/src/dashboard/docs/settings-tool-security.html +0 -176
- package/src/dashboard/docs/settings.html +0 -280
- package/src/dashboard/docs/skill-connections.html +0 -270
- package/src/dashboard/docs/skills.html +0 -206
- package/src/dashboard/docs/task-pipeline.html +0 -261
- package/src/dashboard/docs/transport-encryption.html +0 -359
- package/src/dashboard/docs/users.html +0 -225
- package/src/dashboard/docs/vault.html +0 -260
- package/src/dashboard/docs/workforce.html +0 -245
- package/src/dashboard/index.html +0 -444
- package/src/dashboard/pages/activity.js +0 -379
- package/src/dashboard/pages/agent-detail/activity.js +0 -277
- package/src/dashboard/pages/agent-detail/autonomy.js +0 -244
- package/src/dashboard/pages/agent-detail/budget.js +0 -269
- package/src/dashboard/pages/agent-detail/channels.js +0 -494
- package/src/dashboard/pages/agent-detail/communication.js +0 -296
- package/src/dashboard/pages/agent-detail/configuration.js +0 -882
- package/src/dashboard/pages/agent-detail/deployment.js +0 -958
- package/src/dashboard/pages/agent-detail/email.js +0 -674
- package/src/dashboard/pages/agent-detail/guardrails.js +0 -521
- package/src/dashboard/pages/agent-detail/index.js +0 -261
- package/src/dashboard/pages/agent-detail/manager.js +0 -357
- package/src/dashboard/pages/agent-detail/meeting-browser.js +0 -933
- package/src/dashboard/pages/agent-detail/memory.js +0 -368
- package/src/dashboard/pages/agent-detail/overview.js +0 -844
- package/src/dashboard/pages/agent-detail/permissions.js +0 -1163
- package/src/dashboard/pages/agent-detail/personal-details.js +0 -404
- package/src/dashboard/pages/agent-detail/security.js +0 -409
- package/src/dashboard/pages/agent-detail/shared.js +0 -85
- package/src/dashboard/pages/agent-detail/skills-section.js +0 -183
- package/src/dashboard/pages/agent-detail/tool-security.js +0 -380
- package/src/dashboard/pages/agent-detail/tools.js +0 -322
- package/src/dashboard/pages/agent-detail/whatsapp.js +0 -824
- package/src/dashboard/pages/agent-detail/workforce.js +0 -683
- package/src/dashboard/pages/agents.js +0 -1242
- package/src/dashboard/pages/approvals.js +0 -100
- package/src/dashboard/pages/audit.js +0 -198
- package/src/dashboard/pages/cluster.js +0 -512
- package/src/dashboard/pages/community-skills.js +0 -1219
- package/src/dashboard/pages/compliance.js +0 -475
- package/src/dashboard/pages/dashboard.js +0 -180
- package/src/dashboard/pages/database-access.js +0 -812
- package/src/dashboard/pages/dlp.js +0 -293
- package/src/dashboard/pages/domain-status.js +0 -951
- package/src/dashboard/pages/guardrails.js +0 -1035
- package/src/dashboard/pages/journal.js +0 -172
- package/src/dashboard/pages/knowledge-contributions.js +0 -1682
- package/src/dashboard/pages/knowledge-import.js +0 -455
- package/src/dashboard/pages/knowledge.js +0 -582
- package/src/dashboard/pages/login.js +0 -1056
- package/src/dashboard/pages/memory-transfer.js +0 -631
- package/src/dashboard/pages/messages.js +0 -303
- package/src/dashboard/pages/org-chart.js +0 -349
- package/src/dashboard/pages/organizations.js +0 -1081
- package/src/dashboard/pages/roles.js +0 -780
- package/src/dashboard/pages/settings.js +0 -3790
- package/src/dashboard/pages/skill-connections.js +0 -982
- package/src/dashboard/pages/skills.js +0 -879
- package/src/dashboard/pages/task-pipeline.js +0 -684
- package/src/dashboard/pages/users.js +0 -867
- package/src/dashboard/pages/vault.js +0 -791
- package/src/dashboard/pages/workforce.js +0 -851
- package/src/dashboard/vendor/react-dom.development.js +0 -29924
- package/src/dashboard/vendor/react-dom.production.min.js +0 -267
- package/src/dashboard/vendor/react.development.js +0 -3343
- package/src/dashboard/vendor/react.production.min.js +0 -31
- package/src/database-access/agent-tools.ts +0 -193
- package/src/database-access/connection-manager.ts +0 -1341
- package/src/database-access/index.ts +0 -21
- package/src/database-access/query-sanitizer.ts +0 -220
- package/src/database-access/routes.ts +0 -226
- package/src/database-access/types.ts +0 -226
- package/src/db/adapter.ts +0 -510
- package/src/db/dynamodb.ts +0 -454
- package/src/db/factory.ts +0 -129
- package/src/db/mongodb.ts +0 -360
- package/src/db/mysql.ts +0 -531
- package/src/db/postgres.ts +0 -863
- package/src/db/proxy.ts +0 -39
- package/src/db/resolve-driver.ts +0 -29
- package/src/db/sql-schema.ts +0 -124
- package/src/db/sqlite.ts +0 -493
- package/src/db/turso.ts +0 -470
- package/src/deploy/fly.ts +0 -368
- package/src/deploy/managed.ts +0 -235
- package/src/domain-lock/cli-recover.ts +0 -591
- package/src/domain-lock/cli-verify.ts +0 -190
- package/src/domain-lock/index.ts +0 -220
- package/src/engine/activity-routes.ts +0 -154
- package/src/engine/activity.ts +0 -568
- package/src/engine/agent-autonomy.ts +0 -974
- package/src/engine/agent-config.ts +0 -646
- package/src/engine/agent-heartbeat.ts +0 -720
- package/src/engine/agent-hierarchy.ts +0 -1064
- package/src/engine/agent-memory.ts +0 -806
- package/src/engine/agent-notify.ts +0 -50
- package/src/engine/agent-routes.ts +0 -2583
- package/src/engine/agent-status.ts +0 -311
- package/src/engine/ambient-memory.ts +0 -401
- package/src/engine/approvals.ts +0 -615
- package/src/engine/assets/thinking-hum.mp3 +0 -0
- package/src/engine/catalog-routes.ts +0 -232
- package/src/engine/chat-poller.ts +0 -913
- package/src/engine/chat-webhook-routes.ts +0 -304
- package/src/engine/cli-build-skill.ts +0 -285
- package/src/engine/cli-submit-skill.ts +0 -200
- package/src/engine/cli-validate.ts +0 -188
- package/src/engine/cluster.ts +0 -278
- package/src/engine/communication-routes.ts +0 -139
- package/src/engine/communication.ts +0 -765
- package/src/engine/community-registry.ts +0 -1529
- package/src/engine/community-routes.ts +0 -260
- package/src/engine/compliance-routes.ts +0 -133
- package/src/engine/compliance.ts +0 -1679
- package/src/engine/config-bus.ts +0 -103
- package/src/engine/db-adapter.ts +0 -1156
- package/src/engine/db-schema.ts +0 -1945
- package/src/engine/deploy-schema-routes.ts +0 -176
- package/src/engine/deployer.ts +0 -957
- package/src/engine/dlp-routes.ts +0 -101
- package/src/engine/dlp.ts +0 -410
- package/src/engine/email-poller.ts +0 -855
- package/src/engine/emoji.ts +0 -106
- package/src/engine/guardrail-routes.ts +0 -125
- package/src/engine/guardrails.ts +0 -465
- package/src/engine/index.ts +0 -255
- package/src/engine/journal-routes.ts +0 -56
- package/src/engine/journal.ts +0 -249
- package/src/engine/knowledge-contribution-routes.ts +0 -633
- package/src/engine/knowledge-contribution.ts +0 -1386
- package/src/engine/knowledge-import/chunker.ts +0 -241
- package/src/engine/knowledge-import/import-manager.ts +0 -416
- package/src/engine/knowledge-import/index.ts +0 -27
- package/src/engine/knowledge-import/processors/clean.ts +0 -149
- package/src/engine/knowledge-import/processors/extract-gdrive.ts +0 -102
- package/src/engine/knowledge-import/processors/extract-github.ts +0 -74
- package/src/engine/knowledge-import/processors/extract-sharepoint.ts +0 -69
- package/src/engine/knowledge-import/processors/extract-web.ts +0 -275
- package/src/engine/knowledge-import/processors/index.ts +0 -18
- package/src/engine/knowledge-import/processors/pipeline.ts +0 -171
- package/src/engine/knowledge-import/processors/types.ts +0 -78
- package/src/engine/knowledge-import/processors/validate.ts +0 -150
- package/src/engine/knowledge-import/provider-file-upload.ts +0 -95
- package/src/engine/knowledge-import/provider-github.ts +0 -144
- package/src/engine/knowledge-import/provider-google-sites.ts +0 -323
- package/src/engine/knowledge-import/provider-sharepoint.ts +0 -276
- package/src/engine/knowledge-import/provider-url.ts +0 -218
- package/src/engine/knowledge-import/routes.ts +0 -94
- package/src/engine/knowledge-import/types.ts +0 -92
- package/src/engine/knowledge-routes.ts +0 -231
- package/src/engine/knowledge.ts +0 -587
- package/src/engine/lifecycle.ts +0 -1420
- package/src/engine/mcp-process-manager.ts +0 -573
- package/src/engine/meeting-monitor.ts +0 -483
- package/src/engine/meeting-voice-intelligence.ts +0 -340
- package/src/engine/memory-routes.ts +0 -142
- package/src/engine/memory-transfer-routes.ts +0 -339
- package/src/engine/messaging-history.ts +0 -177
- package/src/engine/messaging-poller.ts +0 -786
- package/src/engine/model-fallback.ts +0 -141
- package/src/engine/oauth-connect-routes.ts +0 -603
- package/src/engine/oauth-connect.ts +0 -304
- package/src/engine/onboarding-routes.ts +0 -148
- package/src/engine/onboarding.ts +0 -574
- package/src/engine/org-approval-routes.ts +0 -146
- package/src/engine/org-integration-routes.ts +0 -399
- package/src/engine/org-integrations.ts +0 -608
- package/src/engine/org-policies.ts +0 -502
- package/src/engine/policy-import-routes.ts +0 -125
- package/src/engine/policy-import.ts +0 -1186
- package/src/engine/policy-routes.ts +0 -163
- package/src/engine/routes.ts +0 -1236
- package/src/engine/screen-unlock.ts +0 -136
- package/src/engine/session-router.ts +0 -212
- package/src/engine/skill-updater-routes.ts +0 -132
- package/src/engine/skill-updater.ts +0 -480
- package/src/engine/skill-validator.ts +0 -331
- package/src/engine/skills/agent-management.ts +0 -119
- package/src/engine/skills/agent-memory.ts +0 -19
- package/src/engine/skills/agenticmail.ts +0 -116
- package/src/engine/skills/core-tools.ts +0 -25
- package/src/engine/skills/database-access.ts +0 -78
- package/src/engine/skills/enterprise-code-sandbox.ts +0 -113
- package/src/engine/skills/enterprise-database.ts +0 -123
- package/src/engine/skills/enterprise-diff.ts +0 -95
- package/src/engine/skills/enterprise-documents.ts +0 -162
- package/src/engine/skills/enterprise-http.ts +0 -99
- package/src/engine/skills/enterprise-security-scan.ts +0 -125
- package/src/engine/skills/enterprise-spreadsheet.ts +0 -171
- package/src/engine/skills/gws-admin.ts +0 -18
- package/src/engine/skills/gws-calendar.ts +0 -21
- package/src/engine/skills/gws-chat.ts +0 -29
- package/src/engine/skills/gws-contacts.ts +0 -20
- package/src/engine/skills/gws-docs.ts +0 -18
- package/src/engine/skills/gws-drive.ts +0 -23
- package/src/engine/skills/gws-forms.ts +0 -23
- package/src/engine/skills/gws-gmail.ts +0 -30
- package/src/engine/skills/gws-groups.ts +0 -17
- package/src/engine/skills/gws-keep.ts +0 -17
- package/src/engine/skills/gws-maps.ts +0 -25
- package/src/engine/skills/gws-meet.ts +0 -23
- package/src/engine/skills/gws-sheets.ts +0 -22
- package/src/engine/skills/gws-sites.ts +0 -16
- package/src/engine/skills/gws-slides.ts +0 -27
- package/src/engine/skills/gws-tasks.ts +0 -22
- package/src/engine/skills/gws-vault.ts +0 -17
- package/src/engine/skills/index.ts +0 -159
- package/src/engine/skills/knowledge-search.ts +0 -18
- package/src/engine/skills/local-system.ts +0 -61
- package/src/engine/skills/m365-admin.ts +0 -18
- package/src/engine/skills/m365-bookings.ts +0 -17
- package/src/engine/skills/m365-copilot.ts +0 -17
- package/src/engine/skills/m365-excel.ts +0 -60
- package/src/engine/skills/m365-forms.ts +0 -17
- package/src/engine/skills/m365-onedrive.ts +0 -60
- package/src/engine/skills/m365-onenote.ts +0 -17
- package/src/engine/skills/m365-outlook.ts +0 -27
- package/src/engine/skills/m365-planner.ts +0 -18
- package/src/engine/skills/m365-power-automate.ts +0 -18
- package/src/engine/skills/m365-power-bi.ts +0 -19
- package/src/engine/skills/m365-powerpoint.ts +0 -33
- package/src/engine/skills/m365-sharepoint.ts +0 -20
- package/src/engine/skills/m365-teams.ts +0 -21
- package/src/engine/skills/m365-todo.ts +0 -17
- package/src/engine/skills/m365-whiteboard.ts +0 -16
- package/src/engine/skills/m365-word.ts +0 -42
- package/src/engine/skills/mcp-bridge.ts +0 -45
- package/src/engine/skills/meeting-lifecycle.ts +0 -20
- package/src/engine/skills/messaging.ts +0 -46
- package/src/engine/skills/visual-memory.ts +0 -25
- package/src/engine/skills.ts +0 -688
- package/src/engine/soul-library.ts +0 -142
- package/src/engine/soul-templates.json +0 -1525
- package/src/engine/storage-manager.ts +0 -252
- package/src/engine/storage-routes.ts +0 -113
- package/src/engine/storage.ts +0 -528
- package/src/engine/task-poller.ts +0 -394
- package/src/engine/task-queue-after-spawn.ts +0 -66
- package/src/engine/task-queue-before-spawn.ts +0 -113
- package/src/engine/task-queue-routes.ts +0 -161
- package/src/engine/task-queue.ts +0 -664
- package/src/engine/tenant.ts +0 -409
- package/src/engine/tool-catalog.ts +0 -354
- package/src/engine/vault-routes.ts +0 -134
- package/src/engine/vault.ts +0 -601
- package/src/engine/workforce-routes.ts +0 -331
- package/src/engine/workforce.ts +0 -1161
- package/src/index.ts +0 -77
- package/src/lib/cidr.ts +0 -122
- package/src/lib/config-store.ts +0 -86
- package/src/lib/resilience.ts +0 -326
- package/src/lib/text-search.ts +0 -358
- package/src/mcp/adapters/activecampaign.adapter.ts +0 -391
- package/src/mcp/adapters/adobe-sign.adapter.ts +0 -469
- package/src/mcp/adapters/adp.adapter.ts +0 -358
- package/src/mcp/adapters/airtable.adapter.ts +0 -273
- package/src/mcp/adapters/apollo.adapter.ts +0 -420
- package/src/mcp/adapters/asana.adapter.ts +0 -315
- package/src/mcp/adapters/auth0.adapter.ts +0 -386
- package/src/mcp/adapters/aws.adapter.ts +0 -345
- package/src/mcp/adapters/azure-devops.adapter.ts +0 -389
- package/src/mcp/adapters/bamboohr.adapter.ts +0 -376
- package/src/mcp/adapters/basecamp.adapter.ts +0 -366
- package/src/mcp/adapters/bigcommerce.adapter.ts +0 -429
- package/src/mcp/adapters/bitbucket.adapter.ts +0 -260
- package/src/mcp/adapters/box.adapter.ts +0 -350
- package/src/mcp/adapters/brex.adapter.ts +0 -367
- package/src/mcp/adapters/buffer.adapter.ts +0 -303
- package/src/mcp/adapters/calendly.adapter.ts +0 -262
- package/src/mcp/adapters/canva.adapter.ts +0 -256
- package/src/mcp/adapters/chargebee.adapter.ts +0 -448
- package/src/mcp/adapters/circleci.adapter.ts +0 -216
- package/src/mcp/adapters/clickup.adapter.ts +0 -335
- package/src/mcp/adapters/close.adapter.ts +0 -390
- package/src/mcp/adapters/cloudflare.adapter.ts +0 -378
- package/src/mcp/adapters/confluence.adapter.ts +0 -301
- package/src/mcp/adapters/contentful.adapter.ts +0 -355
- package/src/mcp/adapters/copper.adapter.ts +0 -468
- package/src/mcp/adapters/crisp.adapter.ts +0 -415
- package/src/mcp/adapters/crowdstrike.adapter.ts +0 -413
- package/src/mcp/adapters/datadog.adapter.ts +0 -373
- package/src/mcp/adapters/digitalocean.adapter.ts +0 -336
- package/src/mcp/adapters/discord.adapter.ts +0 -248
- package/src/mcp/adapters/docker.adapter.ts +0 -238
- package/src/mcp/adapters/docusign.adapter.ts +0 -431
- package/src/mcp/adapters/drift.adapter.ts +0 -386
- package/src/mcp/adapters/dropbox.adapter.ts +0 -315
- package/src/mcp/adapters/figma.adapter.ts +0 -302
- package/src/mcp/adapters/firebase.adapter.ts +0 -446
- package/src/mcp/adapters/flyio.adapter.ts +0 -302
- package/src/mcp/adapters/freshbooks.adapter.ts +0 -474
- package/src/mcp/adapters/freshdesk.adapter.ts +0 -441
- package/src/mcp/adapters/freshsales.adapter.ts +0 -457
- package/src/mcp/adapters/freshservice.adapter.ts +0 -481
- package/src/mcp/adapters/front.adapter.ts +0 -357
- package/src/mcp/adapters/github-actions.adapter.ts +0 -329
- package/src/mcp/adapters/github.adapter.ts +0 -387
- package/src/mcp/adapters/gitlab.adapter.ts +0 -368
- package/src/mcp/adapters/gong.adapter.ts +0 -386
- package/src/mcp/adapters/google-ads.adapter.ts +0 -363
- package/src/mcp/adapters/google-analytics.adapter.ts +0 -316
- package/src/mcp/adapters/google-cloud.adapter.ts +0 -312
- package/src/mcp/adapters/gotomeeting.adapter.ts +0 -255
- package/src/mcp/adapters/grafana.adapter.ts +0 -361
- package/src/mcp/adapters/greenhouse.adapter.ts +0 -354
- package/src/mcp/adapters/gusto.adapter.ts +0 -329
- package/src/mcp/adapters/hashicorp-vault.adapter.ts +0 -355
- package/src/mcp/adapters/heroku.adapter.ts +0 -291
- package/src/mcp/adapters/hibob.adapter.ts +0 -334
- package/src/mcp/adapters/hootsuite.adapter.ts +0 -322
- package/src/mcp/adapters/hubspot.adapter.ts +0 -400
- package/src/mcp/adapters/huggingface.adapter.ts +0 -349
- package/src/mcp/adapters/index.ts +0 -524
- package/src/mcp/adapters/intercom.adapter.ts +0 -269
- package/src/mcp/adapters/jira.adapter.ts +0 -482
- package/src/mcp/adapters/klaviyo.adapter.ts +0 -353
- package/src/mcp/adapters/kubernetes.adapter.ts +0 -431
- package/src/mcp/adapters/lattice.adapter.ts +0 -339
- package/src/mcp/adapters/launchdarkly.adapter.ts +0 -368
- package/src/mcp/adapters/lever.adapter.ts +0 -347
- package/src/mcp/adapters/linear.adapter.ts +0 -300
- package/src/mcp/adapters/linkedin.adapter.ts +0 -331
- package/src/mcp/adapters/livechat.adapter.ts +0 -259
- package/src/mcp/adapters/loom.adapter.ts +0 -230
- package/src/mcp/adapters/mailchimp.adapter.ts +0 -394
- package/src/mcp/adapters/mailgun.adapter.ts +0 -425
- package/src/mcp/adapters/miro.adapter.ts +0 -274
- package/src/mcp/adapters/mixpanel.adapter.ts +0 -324
- package/src/mcp/adapters/monday.adapter.ts +0 -308
- package/src/mcp/adapters/mongodb-atlas.adapter.ts +0 -345
- package/src/mcp/adapters/neon.adapter.ts +0 -312
- package/src/mcp/adapters/netlify.adapter.ts +0 -324
- package/src/mcp/adapters/netsuite.adapter.ts +0 -411
- package/src/mcp/adapters/newrelic.adapter.ts +0 -339
- package/src/mcp/adapters/notion.adapter.ts +0 -338
- package/src/mcp/adapters/okta.adapter.ts +0 -394
- package/src/mcp/adapters/openai.adapter.ts +0 -315
- package/src/mcp/adapters/opsgenie.adapter.ts +0 -375
- package/src/mcp/adapters/outreach.adapter.ts +0 -372
- package/src/mcp/adapters/paddle.adapter.ts +0 -467
- package/src/mcp/adapters/pagerduty.adapter.ts +0 -412
- package/src/mcp/adapters/pandadoc.adapter.ts +0 -389
- package/src/mcp/adapters/paypal.adapter.ts +0 -465
- package/src/mcp/adapters/personio.adapter.ts +0 -401
- package/src/mcp/adapters/pinecone.adapter.ts +0 -340
- package/src/mcp/adapters/pipedrive.adapter.ts +0 -324
- package/src/mcp/adapters/plaid.adapter.ts +0 -444
- package/src/mcp/adapters/postmark.adapter.ts +0 -387
- package/src/mcp/adapters/power-automate.adapter.ts +0 -388
- package/src/mcp/adapters/quickbooks.adapter.ts +0 -431
- package/src/mcp/adapters/recurly.adapter.ts +0 -433
- package/src/mcp/adapters/reddit.adapter.ts +0 -371
- package/src/mcp/adapters/render.adapter.ts +0 -332
- package/src/mcp/adapters/ringcentral.adapter.ts +0 -281
- package/src/mcp/adapters/rippling.adapter.ts +0 -287
- package/src/mcp/adapters/salesforce.adapter.ts +0 -321
- package/src/mcp/adapters/salesloft.adapter.ts +0 -413
- package/src/mcp/adapters/sanity.adapter.ts +0 -363
- package/src/mcp/adapters/sap.adapter.ts +0 -483
- package/src/mcp/adapters/segment.adapter.ts +0 -260
- package/src/mcp/adapters/sendgrid.adapter.ts +0 -265
- package/src/mcp/adapters/sentry.adapter.ts +0 -331
- package/src/mcp/adapters/servicenow.adapter.ts +0 -468
- package/src/mcp/adapters/shopify.adapter.ts +0 -451
- package/src/mcp/adapters/shortcut.adapter.ts +0 -290
- package/src/mcp/adapters/slack.adapter.ts +0 -380
- package/src/mcp/adapters/smartsheet.adapter.ts +0 -326
- package/src/mcp/adapters/snowflake.adapter.ts +0 -347
- package/src/mcp/adapters/snyk.adapter.ts +0 -394
- package/src/mcp/adapters/splunk.adapter.ts +0 -403
- package/src/mcp/adapters/square.adapter.ts +0 -467
- package/src/mcp/adapters/statuspage.adapter.ts +0 -401
- package/src/mcp/adapters/stripe.adapter.ts +0 -380
- package/src/mcp/adapters/supabase.adapter.ts +0 -334
- package/src/mcp/adapters/teamwork.adapter.ts +0 -404
- package/src/mcp/adapters/telegram.adapter.ts +0 -299
- package/src/mcp/adapters/terraform.adapter.ts +0 -300
- package/src/mcp/adapters/todoist.adapter.ts +0 -239
- package/src/mcp/adapters/trello.adapter.ts +0 -316
- package/src/mcp/adapters/twilio.adapter.ts +0 -233
- package/src/mcp/adapters/twitter.adapter.ts +0 -348
- package/src/mcp/adapters/vercel.adapter.ts +0 -219
- package/src/mcp/adapters/weaviate.adapter.ts +0 -371
- package/src/mcp/adapters/webex.adapter.ts +0 -237
- package/src/mcp/adapters/webflow.adapter.ts +0 -287
- package/src/mcp/adapters/whatsapp.adapter.ts +0 -273
- package/src/mcp/adapters/whereby.adapter.ts +0 -240
- package/src/mcp/adapters/woocommerce.adapter.ts +0 -454
- package/src/mcp/adapters/wordpress.adapter.ts +0 -455
- package/src/mcp/adapters/workday.adapter.ts +0 -354
- package/src/mcp/adapters/wrike.adapter.ts +0 -349
- package/src/mcp/adapters/xero.adapter.ts +0 -472
- package/src/mcp/adapters/youtube.adapter.ts +0 -401
- package/src/mcp/adapters/zendesk.adapter.ts +0 -399
- package/src/mcp/adapters/zoho-crm.adapter.ts +0 -410
- package/src/mcp/adapters/zoom.adapter.ts +0 -241
- package/src/mcp/adapters/zuora.adapter.ts +0 -476
- package/src/mcp/framework/api-executor.ts +0 -192
- package/src/mcp/framework/aws-sigv4.ts +0 -216
- package/src/mcp/framework/credential-resolver.ts +0 -128
- package/src/mcp/framework/oauth-token-manager.ts +0 -22
- package/src/mcp/framework/skill-mcp-framework.ts +0 -226
- package/src/mcp/framework/types.ts +0 -130
- package/src/mcp/index.ts +0 -124
- package/src/mcp/integration-catalog.ts +0 -178
- package/src/middleware/dns-rebinding.ts +0 -44
- package/src/middleware/egress-filter.ts +0 -104
- package/src/middleware/firewall.ts +0 -192
- package/src/middleware/geo-ip.ts +0 -156
- package/src/middleware/index.ts +0 -390
- package/src/middleware/network-config.ts +0 -90
- package/src/middleware/proxy-config.ts +0 -71
- package/src/middleware/request-limits.ts +0 -59
- package/src/middleware/transport-encryption.ts +0 -398
- package/src/registry/cli.ts +0 -63
- package/src/registry/server.ts +0 -504
- package/src/runtime/agent-loop.ts +0 -779
- package/src/runtime/compaction.ts +0 -638
- package/src/runtime/email-channel.ts +0 -120
- package/src/runtime/environment.ts +0 -300
- package/src/runtime/followup.ts +0 -211
- package/src/runtime/gateway.ts +0 -260
- package/src/runtime/hooks.ts +0 -564
- package/src/runtime/index.ts +0 -1110
- package/src/runtime/llm-client.ts +0 -1056
- package/src/runtime/model-router.ts +0 -97
- package/src/runtime/providers.ts +0 -228
- package/src/runtime/session-manager.ts +0 -345
- package/src/runtime/subagent.ts +0 -153
- package/src/runtime/tool-executor.ts +0 -208
- package/src/runtime/types.ts +0 -255
- package/src/security/brute-force.ts +0 -423
- package/src/security/config.ts +0 -159
- package/src/security/csp.ts +0 -407
- package/src/security/external-content.ts +0 -299
- package/src/security/index.ts +0 -557
- package/src/security/input-sanitizer.ts +0 -452
- package/src/security/output-filter.ts +0 -575
- package/src/security/port-scanner.ts +0 -342
- package/src/security/prompt-guard.ts +0 -387
- package/src/security/sql-guard.ts +0 -338
- package/src/security/threat-logger.ts +0 -484
- package/src/server.ts +0 -828
- package/src/setup/company.ts +0 -183
- package/src/setup/database.ts +0 -153
- package/src/setup/deployment.ts +0 -561
- package/src/setup/domain.ts +0 -112
- package/src/setup/index.ts +0 -171
- package/src/setup/provision.ts +0 -532
- package/src/setup/registration.ts +0 -302
- package/src/system-prompts/catchup.ts +0 -48
- package/src/system-prompts/google/calendar.ts +0 -37
- package/src/system-prompts/google/chat.ts +0 -92
- package/src/system-prompts/google/contacts.ts +0 -25
- package/src/system-prompts/google/docs.ts +0 -29
- package/src/system-prompts/google/drive.ts +0 -34
- package/src/system-prompts/google/forms.ts +0 -25
- package/src/system-prompts/google/gmail.ts +0 -50
- package/src/system-prompts/google/index.ts +0 -23
- package/src/system-prompts/google/maps.ts +0 -20
- package/src/system-prompts/google/meet.ts +0 -130
- package/src/system-prompts/google/sheets.ts +0 -32
- package/src/system-prompts/google/slides.ts +0 -26
- package/src/system-prompts/google/tasks.ts +0 -27
- package/src/system-prompts/index.ts +0 -88
- package/src/system-prompts/microsoft/contacts.ts +0 -34
- package/src/system-prompts/microsoft/excel.ts +0 -52
- package/src/system-prompts/microsoft/index.ts +0 -31
- package/src/system-prompts/microsoft/onedrive.ts +0 -41
- package/src/system-prompts/microsoft/onenote.ts +0 -36
- package/src/system-prompts/microsoft/outlook-calendar.ts +0 -37
- package/src/system-prompts/microsoft/outlook-mail.ts +0 -46
- package/src/system-prompts/microsoft/planner.ts +0 -37
- package/src/system-prompts/microsoft/powerbi.ts +0 -38
- package/src/system-prompts/microsoft/powerpoint.ts +0 -35
- package/src/system-prompts/microsoft/sharepoint.ts +0 -44
- package/src/system-prompts/microsoft/teams.ts +0 -49
- package/src/system-prompts/microsoft/todo.ts +0 -37
- package/src/system-prompts/shared-blocks.ts +0 -87
- package/src/system-prompts/task.ts +0 -21
- package/src/system-prompts/triage.ts +0 -34
- package/src/types/hono-env.ts +0 -18
- package/src/types/optional-deps.d.ts +0 -10
- /package/{src → dist}/dashboard/HELP-TOOLTIPS-GUIDE.md +0 -0
|
@@ -1,1341 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database Connection Manager
|
|
3
|
-
*
|
|
4
|
-
* Manages connection pools for all supported database types.
|
|
5
|
-
* Handles: connection lifecycle, pooling, health checks, SSH tunnels.
|
|
6
|
-
*
|
|
7
|
-
* All credentials are loaded from the SecureVault — never stored in memory
|
|
8
|
-
* longer than needed for connection establishment.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type {
|
|
12
|
-
DatabaseType,
|
|
13
|
-
DatabaseConnectionConfig,
|
|
14
|
-
AgentDatabaseAccess,
|
|
15
|
-
DatabaseQuery,
|
|
16
|
-
QueryResult,
|
|
17
|
-
ConnectionPoolStats,
|
|
18
|
-
DatabasePermission,
|
|
19
|
-
} from './types.js';
|
|
20
|
-
import { sanitizeQuery, sanitizeForLogging, type SanitizeResult } from './query-sanitizer.js';
|
|
21
|
-
import crypto from 'crypto';
|
|
22
|
-
|
|
23
|
-
// ─── Driver Interfaces ───────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
interface DatabaseDriver {
|
|
26
|
-
connect(config: DatabaseConnectionConfig, credentials: ConnectionCredentials): Promise<DatabaseConnection>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface DatabaseConnection {
|
|
30
|
-
query(sql: string, params?: any[]): Promise<{ rows: any[]; fields?: { name: string; type: string }[]; affectedRows?: number }>;
|
|
31
|
-
close(): Promise<void>;
|
|
32
|
-
ping(): Promise<boolean>;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
interface ConnectionCredentials {
|
|
36
|
-
password?: string;
|
|
37
|
-
connectionString?: string;
|
|
38
|
-
sshPrivateKey?: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ─── Connection Pool Entry ───────────────────────────────────────────────────
|
|
42
|
-
|
|
43
|
-
interface PoolEntry {
|
|
44
|
-
connection: DatabaseConnection;
|
|
45
|
-
connectionId: string;
|
|
46
|
-
createdAt: number;
|
|
47
|
-
lastUsedAt: number;
|
|
48
|
-
inUse: boolean;
|
|
49
|
-
queryCount: number;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ─── Rate Limiter ────────────────────────────────────────────────────────────
|
|
53
|
-
|
|
54
|
-
class RateLimiter {
|
|
55
|
-
private windows = new Map<string, { count: number; resetAt: number }>();
|
|
56
|
-
|
|
57
|
-
check(key: string, maxPerMinute: number): boolean {
|
|
58
|
-
const now = Date.now();
|
|
59
|
-
const window = this.windows.get(key);
|
|
60
|
-
if (!window || window.resetAt <= now) {
|
|
61
|
-
this.windows.set(key, { count: 1, resetAt: now + 60_000 });
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
if (window.count >= maxPerMinute) return false;
|
|
65
|
-
window.count++;
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// ─── Audit Logger ────────────────────────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
interface AuditLogDeps {
|
|
73
|
-
engineDb?: { execute(sql: string, params?: any[]): Promise<any> };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ─── Connection Manager ──────────────────────────────────────────────────────
|
|
77
|
-
|
|
78
|
-
export class DatabaseConnectionManager {
|
|
79
|
-
private pools = new Map<string, PoolEntry[]>();
|
|
80
|
-
private configs = new Map<string, DatabaseConnectionConfig>();
|
|
81
|
-
private agentAccess = new Map<string, AgentDatabaseAccess[]>(); // agentId → accesses
|
|
82
|
-
private drivers = new Map<DatabaseType, DatabaseDriver>();
|
|
83
|
-
private rateLimiter = new RateLimiter();
|
|
84
|
-
private stats = new Map<string, { queries: number; errors: number; totalTimeMs: number; lastActivity: number }>();
|
|
85
|
-
private engineDb?: { run?(sql: string, params?: any[]): Promise<any>; execute?(sql: string, params?: any[]): Promise<any>; all?(sql: string, params?: any[]): Promise<any[]>; get?(sql: string, params?: any[]): Promise<any> };
|
|
86
|
-
private vault?: {
|
|
87
|
-
storeSecret(orgId: string, name: string, category: string, plaintext: string, metadata?: Record<string, any>): Promise<any>;
|
|
88
|
-
getSecret(id: string): Promise<{ entry: any; decrypted: string } | null>;
|
|
89
|
-
getSecretByName(orgId: string, name: string, category?: string): Promise<{ plaintext: string } | null>;
|
|
90
|
-
deleteSecret(id: string): Promise<void>;
|
|
91
|
-
findByName(name: string): any;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
constructor(deps?: { engineDb?: any; vault?: any }) {
|
|
95
|
-
this.engineDb = deps?.engineDb;
|
|
96
|
-
this.vault = deps?.vault;
|
|
97
|
-
this.registerBuiltinDrivers();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// ─── Initialization ──────────────────────────────────────────────────────
|
|
101
|
-
|
|
102
|
-
async setDb(db: any): Promise<void> {
|
|
103
|
-
this.engineDb = db;
|
|
104
|
-
await this.init();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** Normalize DB execute — adapters may have run() or execute() */
|
|
108
|
-
private async dbRun(sql: string, params?: any[]): Promise<any> {
|
|
109
|
-
if (!this.engineDb) throw new Error('No database');
|
|
110
|
-
const fn = this.engineDb.run || this.engineDb.execute;
|
|
111
|
-
if (!fn) throw new Error('DB adapter has no run/execute method');
|
|
112
|
-
return fn.call(this.engineDb, sql, params);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
private async dbAll(sql: string, params?: any[]): Promise<any[]> {
|
|
116
|
-
if (!this.engineDb) return [];
|
|
117
|
-
if (this.engineDb.all) return this.engineDb.all(sql, params) as Promise<any[]>;
|
|
118
|
-
if ((this.engineDb as any).query) {
|
|
119
|
-
const result = await (this.engineDb as any).query(sql, params);
|
|
120
|
-
return Array.isArray(result) ? result : (result?.rows || []);
|
|
121
|
-
}
|
|
122
|
-
// Fallback: execute returns rows for some adapters
|
|
123
|
-
const result = await this.dbRun(sql, params);
|
|
124
|
-
return Array.isArray(result) ? result : (result?.rows || []);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
private async _dbGet(sql: string, params?: any[]): Promise<any> {
|
|
128
|
-
if (!this.engineDb) return null;
|
|
129
|
-
if (this.engineDb.get) return this.engineDb.get(sql, params);
|
|
130
|
-
const rows = await this.dbAll(sql, params);
|
|
131
|
-
return rows?.[0] || null;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async init(): Promise<void> {
|
|
135
|
-
try {
|
|
136
|
-
await this.ensureTable();
|
|
137
|
-
await this.loadConnections();
|
|
138
|
-
await this.loadAgentAccess();
|
|
139
|
-
console.log(`[db-access] Initialized: ${this.configs.size} connections, ${this.agentAccess.size} agent mappings`);
|
|
140
|
-
} catch (err: any) {
|
|
141
|
-
console.error(`[db-access] Init failed: ${err.message}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private async ensureTable(): Promise<void> {
|
|
146
|
-
if (!this.engineDb) return;
|
|
147
|
-
// Detect dialect: try Postgres-style NOW() first, fall back to SQLite datetime('now')
|
|
148
|
-
let isPostgres = false;
|
|
149
|
-
try {
|
|
150
|
-
await this.dbRun(`SELECT NOW()`);
|
|
151
|
-
isPostgres = true;
|
|
152
|
-
} catch {
|
|
153
|
-
isPostgres = false;
|
|
154
|
-
}
|
|
155
|
-
const now = isPostgres ? 'NOW()' : "(datetime('now'))";
|
|
156
|
-
const jsonType = isPostgres ? 'JSONB' : 'TEXT';
|
|
157
|
-
const boolType = isPostgres ? 'BOOLEAN' : 'INTEGER';
|
|
158
|
-
const boolFalse = isPostgres ? 'FALSE' : '0';
|
|
159
|
-
const boolTrue = isPostgres ? 'TRUE' : '1';
|
|
160
|
-
try {
|
|
161
|
-
await this.dbRun(`
|
|
162
|
-
CREATE TABLE IF NOT EXISTS database_connections (
|
|
163
|
-
id TEXT PRIMARY KEY,
|
|
164
|
-
org_id TEXT NOT NULL,
|
|
165
|
-
name TEXT NOT NULL,
|
|
166
|
-
type TEXT NOT NULL,
|
|
167
|
-
config ${jsonType} NOT NULL DEFAULT '{}',
|
|
168
|
-
status TEXT NOT NULL DEFAULT 'inactive',
|
|
169
|
-
last_tested_at TEXT,
|
|
170
|
-
last_error TEXT,
|
|
171
|
-
created_at TEXT NOT NULL DEFAULT ${now},
|
|
172
|
-
updated_at TEXT NOT NULL DEFAULT ${now}
|
|
173
|
-
)
|
|
174
|
-
`);
|
|
175
|
-
await this.dbRun(`
|
|
176
|
-
CREATE TABLE IF NOT EXISTS agent_database_access (
|
|
177
|
-
id TEXT PRIMARY KEY,
|
|
178
|
-
org_id TEXT NOT NULL,
|
|
179
|
-
agent_id TEXT NOT NULL,
|
|
180
|
-
connection_id TEXT NOT NULL REFERENCES database_connections(id) ON DELETE CASCADE,
|
|
181
|
-
permissions TEXT NOT NULL DEFAULT '["read"]',
|
|
182
|
-
query_limits ${jsonType},
|
|
183
|
-
schema_access ${jsonType},
|
|
184
|
-
log_all_queries ${boolType} NOT NULL DEFAULT ${boolFalse},
|
|
185
|
-
require_approval ${boolType} NOT NULL DEFAULT ${boolFalse},
|
|
186
|
-
enabled ${boolType} NOT NULL DEFAULT ${boolTrue},
|
|
187
|
-
created_at TEXT NOT NULL DEFAULT ${now},
|
|
188
|
-
updated_at TEXT NOT NULL DEFAULT ${now},
|
|
189
|
-
UNIQUE(agent_id, connection_id)
|
|
190
|
-
)
|
|
191
|
-
`);
|
|
192
|
-
await this.dbRun(`
|
|
193
|
-
CREATE TABLE IF NOT EXISTS database_audit_log (
|
|
194
|
-
id TEXT PRIMARY KEY,
|
|
195
|
-
org_id TEXT NOT NULL,
|
|
196
|
-
agent_id TEXT NOT NULL,
|
|
197
|
-
agent_name TEXT,
|
|
198
|
-
connection_id TEXT NOT NULL,
|
|
199
|
-
connection_name TEXT,
|
|
200
|
-
operation TEXT NOT NULL,
|
|
201
|
-
query TEXT NOT NULL,
|
|
202
|
-
param_count INTEGER NOT NULL DEFAULT 0,
|
|
203
|
-
rows_affected INTEGER NOT NULL DEFAULT 0,
|
|
204
|
-
execution_time_ms INTEGER NOT NULL DEFAULT 0,
|
|
205
|
-
success ${boolType} NOT NULL DEFAULT ${boolTrue},
|
|
206
|
-
error TEXT,
|
|
207
|
-
timestamp TEXT NOT NULL DEFAULT ${now}
|
|
208
|
-
)
|
|
209
|
-
`);
|
|
210
|
-
// Index for audit log queries
|
|
211
|
-
await this.dbRun(`CREATE INDEX IF NOT EXISTS idx_db_audit_agent ON database_audit_log(agent_id, timestamp)`).catch(() => {});
|
|
212
|
-
await this.dbRun(`CREATE INDEX IF NOT EXISTS idx_db_audit_conn ON database_audit_log(connection_id, timestamp)`).catch(() => {});
|
|
213
|
-
} catch (err: any) {
|
|
214
|
-
console.error(`[db-access] Table creation failed:`, err.message);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
private async loadConnections(): Promise<void> {
|
|
219
|
-
if (!this.engineDb) { console.warn('[db-access] No engineDb, skipping loadConnections'); return; }
|
|
220
|
-
try {
|
|
221
|
-
const rows = await this.dbAll('SELECT * FROM database_connections');
|
|
222
|
-
// Loaded connections from DB
|
|
223
|
-
for (const row of (rows || [])) {
|
|
224
|
-
const config = this.rowToConfig(row);
|
|
225
|
-
this.configs.set(config.id, config);
|
|
226
|
-
}
|
|
227
|
-
} catch (err: any) {
|
|
228
|
-
console.warn(`[db-access] Failed to load connections: ${err.message}`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
private async loadAgentAccess(): Promise<void> {
|
|
233
|
-
if (!this.engineDb) return;
|
|
234
|
-
try {
|
|
235
|
-
const rows = await this.dbAll('SELECT * FROM agent_database_access WHERE enabled IS NOT FALSE');
|
|
236
|
-
for (const row of (rows || [])) {
|
|
237
|
-
const access = this.rowToAccess(row);
|
|
238
|
-
const list = this.agentAccess.get(access.agentId) || [];
|
|
239
|
-
list.push(access);
|
|
240
|
-
this.agentAccess.set(access.agentId, list);
|
|
241
|
-
}
|
|
242
|
-
} catch (err: any) {
|
|
243
|
-
console.warn(`[db-access] Failed to load agent access: ${err.message}`);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// ─── CRUD: Connections ─────────────────────────────────────────────────────
|
|
248
|
-
|
|
249
|
-
async createConnection(config: Omit<DatabaseConnectionConfig, 'id' | 'createdAt' | 'updatedAt'>, credentials?: { password?: string; connectionString?: string }): Promise<DatabaseConnectionConfig> {
|
|
250
|
-
const id = crypto.randomUUID();
|
|
251
|
-
const now = new Date().toISOString();
|
|
252
|
-
const full: DatabaseConnectionConfig = { ...config, id, createdAt: now, updatedAt: now };
|
|
253
|
-
|
|
254
|
-
// Store credentials in vault
|
|
255
|
-
if (credentials?.password && this.vault) {
|
|
256
|
-
await this.vault.storeSecret(config.orgId, `db:${id}:password`, 'database_credential', credentials.password);
|
|
257
|
-
}
|
|
258
|
-
if (credentials?.connectionString && this.vault) {
|
|
259
|
-
await this.vault.storeSecret(config.orgId, `db:${id}:connection_string`, 'database_credential', credentials.connectionString);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Store config (without credentials) in DB
|
|
263
|
-
if (this.engineDb) {
|
|
264
|
-
await this.dbRun(
|
|
265
|
-
`INSERT INTO database_connections (id, org_id, name, type, config, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
266
|
-
[id, full.orgId, full.name, full.type, JSON.stringify(this.configToStorable(full)), full.status, now, now]
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
this.configs.set(id, full);
|
|
271
|
-
console.log(`[db-access] Connection created: ${full.name} (${full.type})`);
|
|
272
|
-
return full;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
async updateConnection(id: string, updates: Partial<DatabaseConnectionConfig>, credentials?: { password?: string; connectionString?: string }): Promise<DatabaseConnectionConfig | null> {
|
|
276
|
-
const existing = this.configs.get(id);
|
|
277
|
-
if (!existing) return null;
|
|
278
|
-
|
|
279
|
-
const updated = { ...existing, ...updates, id, updatedAt: new Date().toISOString() };
|
|
280
|
-
|
|
281
|
-
if (this.vault) {
|
|
282
|
-
if (credentials?.password) {
|
|
283
|
-
const old = this.vault.findByName(`db:${id}:password`);
|
|
284
|
-
if (old) try { await this.vault.deleteSecret(old.id); } catch {}
|
|
285
|
-
await this.vault.storeSecret(existing.orgId, `db:${id}:password`, 'database_credential', credentials.password);
|
|
286
|
-
}
|
|
287
|
-
if (credentials?.connectionString) {
|
|
288
|
-
const old = this.vault.findByName(`db:${id}:connection_string`);
|
|
289
|
-
if (old) try { await this.vault.deleteSecret(old.id); } catch {}
|
|
290
|
-
await this.vault.storeSecret(existing.orgId, `db:${id}:connection_string`, 'database_credential', credentials.connectionString);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (this.engineDb) {
|
|
295
|
-
await this.dbRun(
|
|
296
|
-
`UPDATE database_connections SET name = ?, type = ?, config = ?, status = ?, updated_at = ? WHERE id = ?`,
|
|
297
|
-
[updated.name, updated.type, JSON.stringify(this.configToStorable(updated)), updated.status, updated.updatedAt, id]
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
this.configs.set(id, updated);
|
|
302
|
-
|
|
303
|
-
// Close existing pool connections on config change
|
|
304
|
-
await this.closePool(id);
|
|
305
|
-
|
|
306
|
-
return updated;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
async deleteConnection(id: string): Promise<boolean> {
|
|
310
|
-
const config = this.configs.get(id);
|
|
311
|
-
if (!config) return false;
|
|
312
|
-
|
|
313
|
-
await this.closePool(id);
|
|
314
|
-
|
|
315
|
-
// Remove vault secrets
|
|
316
|
-
if (this.vault) {
|
|
317
|
-
try {
|
|
318
|
-
for (const suffix of ['password', 'connection_string', 'ssh_key']) {
|
|
319
|
-
const entry = this.vault.findByName(`db:${id}:${suffix}`);
|
|
320
|
-
if (entry) await this.vault.deleteSecret(entry.id);
|
|
321
|
-
}
|
|
322
|
-
} catch { /* non-fatal */ }
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (this.engineDb) {
|
|
326
|
-
await this.dbRun('DELETE FROM agent_database_access WHERE connection_id = ?', [id]);
|
|
327
|
-
await this.dbRun('DELETE FROM database_connections WHERE id = ?', [id]);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
this.configs.delete(id);
|
|
331
|
-
// Remove from all agent access lists
|
|
332
|
-
for (const [agentId, list] of this.agentAccess) {
|
|
333
|
-
const filtered = list.filter(a => a.connectionId !== id);
|
|
334
|
-
if (filtered.length === 0) this.agentAccess.delete(agentId);
|
|
335
|
-
else this.agentAccess.set(agentId, filtered);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
console.log(`[db-access] Connection deleted: ${config.name}`);
|
|
339
|
-
return true;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
getConnection(id: string): DatabaseConnectionConfig | undefined {
|
|
343
|
-
return this.configs.get(id);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/** Get a human-readable summary of an agent's database connections for system prompts */
|
|
347
|
-
getAgentConnectionSummary(agentId: string): string[] {
|
|
348
|
-
const accesses = this.getAgentAccess(agentId).filter(a => a.enabled);
|
|
349
|
-
return accesses.map(a => {
|
|
350
|
-
const config = this.configs.get(a.connectionId);
|
|
351
|
-
if (!config) return '';
|
|
352
|
-
const perms = a.permissions?.join(', ') || 'read';
|
|
353
|
-
return `"${config.name}" (${config.type}) — permissions: ${perms}`;
|
|
354
|
-
}).filter(Boolean);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
listConnections(orgId: string): DatabaseConnectionConfig[] {
|
|
358
|
-
return [...this.configs.values()].filter(c => c.orgId === orgId);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// ─── CRUD: Agent Access ────────────────────────────────────────────────────
|
|
362
|
-
|
|
363
|
-
async grantAccess(access: Omit<AgentDatabaseAccess, 'id' | 'createdAt' | 'updatedAt'>): Promise<AgentDatabaseAccess> {
|
|
364
|
-
const id = crypto.randomUUID();
|
|
365
|
-
const now = new Date().toISOString();
|
|
366
|
-
const full: AgentDatabaseAccess = { ...access, id, createdAt: now, updatedAt: now };
|
|
367
|
-
|
|
368
|
-
if (this.engineDb) {
|
|
369
|
-
await this.dbRun(
|
|
370
|
-
`INSERT INTO agent_database_access (id, org_id, agent_id, connection_id, permissions, query_limits, schema_access, log_all_queries, require_approval, enabled, created_at, updated_at)
|
|
371
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
372
|
-
[
|
|
373
|
-
id, full.orgId, full.agentId, full.connectionId,
|
|
374
|
-
JSON.stringify(full.permissions), JSON.stringify(full.queryLimits || null),
|
|
375
|
-
JSON.stringify(full.schemaAccess || null), full.logAllQueries,
|
|
376
|
-
full.requireApproval, full.enabled, now, now,
|
|
377
|
-
]
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const list = this.agentAccess.get(full.agentId) || [];
|
|
382
|
-
list.push(full);
|
|
383
|
-
this.agentAccess.set(full.agentId, list);
|
|
384
|
-
|
|
385
|
-
return full;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
async revokeAccess(agentId: string, connectionId: string): Promise<boolean> {
|
|
389
|
-
if (this.engineDb) {
|
|
390
|
-
await this.dbRun(
|
|
391
|
-
'DELETE FROM agent_database_access WHERE agent_id = ? AND connection_id = ?',
|
|
392
|
-
[agentId, connectionId]
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const list = this.agentAccess.get(agentId) || [];
|
|
397
|
-
const filtered = list.filter(a => a.connectionId !== connectionId);
|
|
398
|
-
if (filtered.length === 0) this.agentAccess.delete(agentId);
|
|
399
|
-
else this.agentAccess.set(agentId, filtered);
|
|
400
|
-
|
|
401
|
-
return true;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
async updateAccess(agentId: string, connectionId: string, updates: Partial<AgentDatabaseAccess>): Promise<AgentDatabaseAccess | null> {
|
|
405
|
-
const list = this.agentAccess.get(agentId) || [];
|
|
406
|
-
const idx = list.findIndex(a => a.connectionId === connectionId);
|
|
407
|
-
if (idx === -1) return null;
|
|
408
|
-
|
|
409
|
-
const updated = { ...list[idx], ...updates, updatedAt: new Date().toISOString() };
|
|
410
|
-
list[idx] = updated;
|
|
411
|
-
this.agentAccess.set(agentId, list);
|
|
412
|
-
|
|
413
|
-
if (this.engineDb) {
|
|
414
|
-
await this.dbRun(
|
|
415
|
-
`UPDATE agent_database_access SET permissions = ?, query_limits = ?, schema_access = ?, log_all_queries = ?, require_approval = ?, enabled = ?, updated_at = ? WHERE agent_id = ? AND connection_id = ?`,
|
|
416
|
-
[
|
|
417
|
-
JSON.stringify(updated.permissions), JSON.stringify(updated.queryLimits || null),
|
|
418
|
-
JSON.stringify(updated.schemaAccess || null), updated.logAllQueries,
|
|
419
|
-
updated.requireApproval, updated.enabled, updated.updatedAt,
|
|
420
|
-
agentId, connectionId,
|
|
421
|
-
]
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
return updated;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
getAgentAccess(agentId: string): AgentDatabaseAccess[] {
|
|
429
|
-
return this.agentAccess.get(agentId) || [];
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
getConnectionAgents(connectionId: string): AgentDatabaseAccess[] {
|
|
433
|
-
const result: AgentDatabaseAccess[] = [];
|
|
434
|
-
for (const list of this.agentAccess.values()) {
|
|
435
|
-
for (const a of list) {
|
|
436
|
-
if (a.connectionId === connectionId) result.push(a);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
return result;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// ─── Query Execution ──────────────────────────────────────────────────────
|
|
443
|
-
|
|
444
|
-
async executeQuery(query: DatabaseQuery): Promise<QueryResult> {
|
|
445
|
-
const startMs = Date.now();
|
|
446
|
-
const queryId = crypto.randomUUID();
|
|
447
|
-
|
|
448
|
-
// 1. Validate agent has access to this connection
|
|
449
|
-
const access = this.getAgentAccess(query.agentId).find(a => a.connectionId === query.connectionId && a.enabled);
|
|
450
|
-
if (!access) {
|
|
451
|
-
return { success: false, error: 'Agent does not have access to this database', executionTimeMs: 0, queryId };
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
const config = this.configs.get(query.connectionId);
|
|
455
|
-
if (!config || config.status !== 'active') {
|
|
456
|
-
return { success: false, error: 'Database connection is not active', executionTimeMs: 0, queryId };
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// 2. Rate limit check
|
|
460
|
-
const rateLimit = access.queryLimits?.maxQueriesPerMinute ?? 60;
|
|
461
|
-
const rateKey = `${query.agentId}:${query.connectionId}`;
|
|
462
|
-
if (!this.rateLimiter.check(rateKey, rateLimit)) {
|
|
463
|
-
return { success: false, error: `Rate limit exceeded (${rateLimit}/min)`, executionTimeMs: 0, queryId };
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// 3. Sanitize SQL query
|
|
467
|
-
if (!query.sql) {
|
|
468
|
-
return { success: false, error: 'No SQL query provided', executionTimeMs: 0, queryId };
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
const sanitizeResult = sanitizeQuery(query.sql, access.permissions, config, access);
|
|
472
|
-
if (!sanitizeResult.allowed) {
|
|
473
|
-
await this.logAudit(query, config, access, 'read', 0, false, sanitizeResult.reason || 'Query blocked', startMs, queryId);
|
|
474
|
-
return { success: false, error: sanitizeResult.reason, executionTimeMs: Date.now() - startMs, queryId };
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const finalSql = sanitizeResult.sanitizedQuery || query.sql;
|
|
478
|
-
|
|
479
|
-
// 4. Check concurrent query limit
|
|
480
|
-
const _maxConcurrent = access.queryLimits?.maxConcurrentQueries ?? config.queryLimits?.maxConcurrentQueries ?? 5;
|
|
481
|
-
// (In production, track active queries per connection — simplified here)
|
|
482
|
-
|
|
483
|
-
// 5. Execute with timeout
|
|
484
|
-
const timeout = access.queryLimits?.queryTimeoutMs ?? config.queryLimits?.queryTimeoutMs ?? 30_000;
|
|
485
|
-
|
|
486
|
-
try {
|
|
487
|
-
const conn = await this.getPooledConnection(query.connectionId);
|
|
488
|
-
|
|
489
|
-
const result = await Promise.race([
|
|
490
|
-
conn.query(finalSql, query.params),
|
|
491
|
-
new Promise<never>((_, reject) => setTimeout(() => reject(new Error('Query timeout')), timeout)),
|
|
492
|
-
]);
|
|
493
|
-
|
|
494
|
-
const execMs = Date.now() - startMs;
|
|
495
|
-
const rows = result.rows || [];
|
|
496
|
-
const affectedRows = result.affectedRows ?? rows.length;
|
|
497
|
-
|
|
498
|
-
// Check row limits
|
|
499
|
-
const maxRows = sanitizeResult.operation === 'read'
|
|
500
|
-
? (access.queryLimits?.maxRowsRead ?? config.queryLimits?.maxRowsRead ?? 10000)
|
|
501
|
-
: sanitizeResult.operation === 'write'
|
|
502
|
-
? (access.queryLimits?.maxRowsWrite ?? config.queryLimits?.maxRowsWrite ?? 1000)
|
|
503
|
-
: (access.queryLimits?.maxRowsDelete ?? config.queryLimits?.maxRowsDelete ?? 100);
|
|
504
|
-
|
|
505
|
-
const truncated = rows.length > maxRows;
|
|
506
|
-
const limitedRows = truncated ? rows.slice(0, maxRows) : rows;
|
|
507
|
-
|
|
508
|
-
// Update stats
|
|
509
|
-
this.updateStats(query.connectionId, execMs, false);
|
|
510
|
-
|
|
511
|
-
// Audit log
|
|
512
|
-
const shouldLog = access.logAllQueries || sanitizeResult.operation !== 'read';
|
|
513
|
-
if (shouldLog) {
|
|
514
|
-
await this.logAudit(query, config, access, sanitizeResult.operation, affectedRows, true, undefined, startMs, queryId);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
return {
|
|
518
|
-
success: true,
|
|
519
|
-
rows: limitedRows,
|
|
520
|
-
rowCount: limitedRows.length,
|
|
521
|
-
affectedRows,
|
|
522
|
-
fields: result.fields,
|
|
523
|
-
executionTimeMs: execMs,
|
|
524
|
-
truncated,
|
|
525
|
-
queryId,
|
|
526
|
-
};
|
|
527
|
-
} catch (err: any) {
|
|
528
|
-
const execMs = Date.now() - startMs;
|
|
529
|
-
this.updateStats(query.connectionId, execMs, true);
|
|
530
|
-
await this.logAudit(query, config, access, sanitizeResult.operation, 0, false, err.message, startMs, queryId);
|
|
531
|
-
return { success: false, error: err.message, executionTimeMs: execMs, queryId };
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// ─── Connection Testing ────────────────────────────────────────────────────
|
|
536
|
-
|
|
537
|
-
async testConnection(connectionId: string): Promise<{ success: boolean; latencyMs: number; error?: string; version?: string }> {
|
|
538
|
-
const config = this.configs.get(connectionId);
|
|
539
|
-
if (!config) return { success: false, latencyMs: 0, error: 'Connection not found' };
|
|
540
|
-
|
|
541
|
-
const startMs = Date.now();
|
|
542
|
-
try {
|
|
543
|
-
const conn = await this.getPooledConnection(connectionId);
|
|
544
|
-
const alive = await conn.ping();
|
|
545
|
-
const latencyMs = Date.now() - startMs;
|
|
546
|
-
|
|
547
|
-
// Update status
|
|
548
|
-
await this.updateConnection(connectionId, {
|
|
549
|
-
status: alive ? 'active' : 'error',
|
|
550
|
-
lastTestedAt: new Date().toISOString(),
|
|
551
|
-
lastError: alive ? undefined : 'Ping failed',
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
return { success: alive, latencyMs, error: alive ? undefined : 'Ping failed — connection may have been closed or timed out. Try reconnecting.' };
|
|
555
|
-
} catch (err: any) {
|
|
556
|
-
// On connection failure, close stale pool and retry once with fresh connection
|
|
557
|
-
try {
|
|
558
|
-
await this.closePool(connectionId);
|
|
559
|
-
const conn = await this.getPooledConnection(connectionId);
|
|
560
|
-
const alive = await conn.ping();
|
|
561
|
-
const latencyMs = Date.now() - startMs;
|
|
562
|
-
await this.updateConnection(connectionId, { status: alive ? 'active' : 'error', lastTestedAt: new Date().toISOString(), lastError: alive ? undefined : 'Ping failed on retry' });
|
|
563
|
-
return { success: alive, latencyMs, error: alive ? undefined : 'Ping failed on retry' };
|
|
564
|
-
} catch (retryErr: any) {
|
|
565
|
-
// Both attempts failed
|
|
566
|
-
}
|
|
567
|
-
const msg = (err instanceof AggregateError ? (err.errors?.map?.((x: any) => x.message).join('; ') || 'Multiple connection failures') : (err.message || String(err))) || 'Unknown connection error';
|
|
568
|
-
await this.updateConnection(connectionId, {
|
|
569
|
-
status: 'error',
|
|
570
|
-
lastTestedAt: new Date().toISOString(),
|
|
571
|
-
lastError: msg,
|
|
572
|
-
});
|
|
573
|
-
return { success: false, latencyMs: Date.now() - startMs, error: msg };
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
/**
|
|
578
|
-
* Test connection parameters without saving — creates a temporary connection,
|
|
579
|
-
* pings it, and immediately destroys it.
|
|
580
|
-
*/
|
|
581
|
-
async testConnectionParams(params: {
|
|
582
|
-
type: string; host?: string; port?: number; database?: string;
|
|
583
|
-
username?: string; password?: string; connectionString?: string; ssl?: boolean;
|
|
584
|
-
}): Promise<{ success: boolean; latencyMs: number; error?: string }> {
|
|
585
|
-
const startMs = Date.now();
|
|
586
|
-
const driver = this.drivers.get(params.type as any);
|
|
587
|
-
if (!driver) return { success: false, latencyMs: 0, error: `No driver for database type: ${params.type}` };
|
|
588
|
-
|
|
589
|
-
let connection: any;
|
|
590
|
-
try {
|
|
591
|
-
connection = await driver.connect(
|
|
592
|
-
{ type: params.type as any, host: params.host, port: params.port, database: params.database, ssl: params.ssl } as any,
|
|
593
|
-
{ password: params.password, connectionString: params.connectionString },
|
|
594
|
-
);
|
|
595
|
-
const alive = await connection.ping();
|
|
596
|
-
const latencyMs = Date.now() - startMs;
|
|
597
|
-
return { success: alive, latencyMs, error: alive ? undefined : 'Ping failed — database responded but health check did not pass' };
|
|
598
|
-
} catch (err: any) {
|
|
599
|
-
return { success: false, latencyMs: Date.now() - startMs, error: err.message || String(err) || 'Connection failed' };
|
|
600
|
-
} finally {
|
|
601
|
-
try { if (connection?.close) await connection.close(); } catch {}
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// ─── Pool Management ───────────────────────────────────────────────────────
|
|
606
|
-
|
|
607
|
-
private async getPooledConnection(connectionId: string): Promise<DatabaseConnection> {
|
|
608
|
-
const pool = this.pools.get(connectionId) || [];
|
|
609
|
-
|
|
610
|
-
// Find idle connection
|
|
611
|
-
const idle = pool.find(p => !p.inUse);
|
|
612
|
-
if (idle) {
|
|
613
|
-
idle.inUse = true;
|
|
614
|
-
idle.lastUsedAt = Date.now();
|
|
615
|
-
return this.wrapPooledConnection(idle);
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
// Create new connection
|
|
619
|
-
const config = this.configs.get(connectionId);
|
|
620
|
-
if (!config) throw new Error('Connection not found');
|
|
621
|
-
|
|
622
|
-
const maxPool = config.pool?.max ?? 10;
|
|
623
|
-
if (pool.length >= maxPool) throw new Error('Connection pool exhausted');
|
|
624
|
-
|
|
625
|
-
const driver = this.drivers.get(config.type);
|
|
626
|
-
if (!driver) throw new Error(`No driver for database type: ${config.type}`);
|
|
627
|
-
|
|
628
|
-
// Load credentials from vault
|
|
629
|
-
const credentials = await this.loadCredentials(config);
|
|
630
|
-
const connection = await driver.connect(config, credentials);
|
|
631
|
-
|
|
632
|
-
const entry: PoolEntry = {
|
|
633
|
-
connection,
|
|
634
|
-
connectionId,
|
|
635
|
-
createdAt: Date.now(),
|
|
636
|
-
lastUsedAt: Date.now(),
|
|
637
|
-
inUse: true,
|
|
638
|
-
queryCount: 0,
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
pool.push(entry);
|
|
642
|
-
this.pools.set(connectionId, pool);
|
|
643
|
-
|
|
644
|
-
return this.wrapPooledConnection(entry);
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
private wrapPooledConnection(entry: PoolEntry): DatabaseConnection {
|
|
648
|
-
return {
|
|
649
|
-
query: async (sql, params) => {
|
|
650
|
-
entry.queryCount++;
|
|
651
|
-
return entry.connection.query(sql, params);
|
|
652
|
-
},
|
|
653
|
-
close: async () => { entry.inUse = false; }, // Return to pool, don't actually close
|
|
654
|
-
ping: () => entry.connection.ping(),
|
|
655
|
-
};
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
private async closePool(connectionId: string): Promise<void> {
|
|
659
|
-
const pool = this.pools.get(connectionId) || [];
|
|
660
|
-
for (const entry of pool) {
|
|
661
|
-
try { await entry.connection.close(); } catch { /* ignore */ }
|
|
662
|
-
}
|
|
663
|
-
this.pools.delete(connectionId);
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
private async loadCredentials(config: DatabaseConnectionConfig): Promise<ConnectionCredentials> {
|
|
667
|
-
const creds: ConnectionCredentials = {};
|
|
668
|
-
if (this.vault) {
|
|
669
|
-
try {
|
|
670
|
-
const pw = await this.vault.getSecretByName(config.orgId, `db:${config.id}:password`, 'database_credential');
|
|
671
|
-
if (pw) creds.password = pw.plaintext;
|
|
672
|
-
} catch { /* no password stored */ }
|
|
673
|
-
try {
|
|
674
|
-
const cs = await this.vault.getSecretByName(config.orgId, `db:${config.id}:connection_string`, 'database_credential');
|
|
675
|
-
if (cs) creds.connectionString = cs.plaintext;
|
|
676
|
-
} catch { /* no connection string stored */ }
|
|
677
|
-
if (config.sshTunnel?.enabled) {
|
|
678
|
-
try {
|
|
679
|
-
const ssh = await this.vault.getSecretByName(config.orgId, `db:${config.id}:ssh_key`, 'database_credential');
|
|
680
|
-
if (ssh) creds.sshPrivateKey = ssh.plaintext;
|
|
681
|
-
} catch { /* no SSH key stored */ }
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
return creds;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// ─── Stats ─────────────────────────────────────────────────────────────────
|
|
688
|
-
|
|
689
|
-
getPoolStats(connectionId: string): ConnectionPoolStats {
|
|
690
|
-
const pool = this.pools.get(connectionId) || [];
|
|
691
|
-
const s = this.stats.get(connectionId) || { queries: 0, errors: 0, totalTimeMs: 0, lastActivity: 0 };
|
|
692
|
-
|
|
693
|
-
return {
|
|
694
|
-
connectionId,
|
|
695
|
-
totalConnections: pool.length,
|
|
696
|
-
activeConnections: pool.filter(p => p.inUse).length,
|
|
697
|
-
idleConnections: pool.filter(p => !p.inUse).length,
|
|
698
|
-
waitingRequests: 0,
|
|
699
|
-
queriesExecuted: s.queries,
|
|
700
|
-
averageQueryTimeMs: s.queries > 0 ? Math.round(s.totalTimeMs / s.queries) : 0,
|
|
701
|
-
errorCount: s.errors,
|
|
702
|
-
lastActivityAt: s.lastActivity ? new Date(s.lastActivity).toISOString() : '',
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
private updateStats(connectionId: string, timeMs: number, isError: boolean): void {
|
|
707
|
-
const s = this.stats.get(connectionId) || { queries: 0, errors: 0, totalTimeMs: 0, lastActivity: 0 };
|
|
708
|
-
s.queries++;
|
|
709
|
-
s.totalTimeMs += timeMs;
|
|
710
|
-
if (isError) s.errors++;
|
|
711
|
-
s.lastActivity = Date.now();
|
|
712
|
-
this.stats.set(connectionId, s);
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
// ─── Audit Logging ─────────────────────────────────────────────────────────
|
|
716
|
-
|
|
717
|
-
private async logAudit(
|
|
718
|
-
query: DatabaseQuery,
|
|
719
|
-
config: DatabaseConnectionConfig,
|
|
720
|
-
_access: AgentDatabaseAccess,
|
|
721
|
-
operation: string,
|
|
722
|
-
rowsAffected: number,
|
|
723
|
-
success: boolean,
|
|
724
|
-
error: string | undefined,
|
|
725
|
-
startMs: number,
|
|
726
|
-
queryId: string,
|
|
727
|
-
): Promise<void> {
|
|
728
|
-
if (!this.engineDb) return;
|
|
729
|
-
try {
|
|
730
|
-
await this.dbRun(
|
|
731
|
-
`INSERT INTO database_audit_log (id, org_id, agent_id, connection_id, connection_name, operation, query, param_count, rows_affected, execution_time_ms, success, error, timestamp)
|
|
732
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
733
|
-
[
|
|
734
|
-
queryId, config.orgId, query.agentId, query.connectionId, config.name,
|
|
735
|
-
operation, sanitizeForLogging(query.sql || ''), (query.params || []).length,
|
|
736
|
-
rowsAffected, Date.now() - startMs, success, error || null,
|
|
737
|
-
new Date().toISOString(),
|
|
738
|
-
]
|
|
739
|
-
);
|
|
740
|
-
} catch (err: any) {
|
|
741
|
-
console.warn(`[db-access] Audit log failed: ${err.message}`);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
async getAuditLog(opts: { orgId: string; agentId?: string; connectionId?: string; limit?: number; offset?: number }): Promise<any[]> {
|
|
746
|
-
if (!this.engineDb) return [];
|
|
747
|
-
const conditions = ['org_id = ?'];
|
|
748
|
-
const params: any[] = [opts.orgId];
|
|
749
|
-
if (opts.agentId) { conditions.push('agent_id = ?'); params.push(opts.agentId); }
|
|
750
|
-
if (opts.connectionId) { conditions.push('connection_id = ?'); params.push(opts.connectionId); }
|
|
751
|
-
params.push(opts.limit ?? 100, opts.offset ?? 0);
|
|
752
|
-
|
|
753
|
-
return this.dbAll(
|
|
754
|
-
`SELECT * FROM database_audit_log WHERE ${conditions.join(' AND ')} ORDER BY timestamp DESC LIMIT ? OFFSET ?`,
|
|
755
|
-
params
|
|
756
|
-
);
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
// ─── Driver Registration ───────────────────────────────────────────────────
|
|
760
|
-
|
|
761
|
-
registerDriver(type: DatabaseType, driver: DatabaseDriver): void {
|
|
762
|
-
this.drivers.set(type, driver);
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
// ─── Auto-Install Helper ──────────────────────────────────────────────────
|
|
766
|
-
|
|
767
|
-
private _installCache = new Set<string>();
|
|
768
|
-
|
|
769
|
-
/**
|
|
770
|
-
* Auto-install a npm package if not already installed.
|
|
771
|
-
* Caches install attempts to avoid repeated installs in the same process.
|
|
772
|
-
*/
|
|
773
|
-
/**
|
|
774
|
-
* Load a package using createRequire (works in bundled builds where dynamic import() fails).
|
|
775
|
-
* Falls back through multiple strategies: createRequire at cwd, createRequire at node_modules, direct import.
|
|
776
|
-
*/
|
|
777
|
-
private _requirePkg(pkg: string): any {
|
|
778
|
-
// Strategy 1: createRequire from cwd (works for npm-installed packages in bundled code)
|
|
779
|
-
try {
|
|
780
|
-
const { createRequire } = require('node:module');
|
|
781
|
-
const req = createRequire(require('node:path').join(process.cwd(), 'node_modules', '.package.json'));
|
|
782
|
-
return req(pkg);
|
|
783
|
-
} catch {}
|
|
784
|
-
// Strategy 2: createRequire from process.cwd package.json
|
|
785
|
-
try {
|
|
786
|
-
const { createRequire } = require('node:module');
|
|
787
|
-
const req = createRequire(require('node:path').join(process.cwd(), 'package.json'));
|
|
788
|
-
return req(pkg);
|
|
789
|
-
} catch {}
|
|
790
|
-
// Strategy 3: resolve absolute path manually
|
|
791
|
-
try {
|
|
792
|
-
const absPath = require('node:path').join(process.cwd(), 'node_modules', pkg);
|
|
793
|
-
return require(absPath);
|
|
794
|
-
} catch {}
|
|
795
|
-
// Strategy 4: plain require (may work in non-bundled contexts)
|
|
796
|
-
try {
|
|
797
|
-
return require(pkg);
|
|
798
|
-
} catch {}
|
|
799
|
-
return null;
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
private async ensurePackage(pkg: string): Promise<any> {
|
|
803
|
-
// Try loading first (multiple strategies for bundled builds)
|
|
804
|
-
const existing = this._requirePkg(pkg);
|
|
805
|
-
if (existing) return existing;
|
|
806
|
-
|
|
807
|
-
// Also try dynamic import as last resort for ESM packages
|
|
808
|
-
try {
|
|
809
|
-
return await import(pkg);
|
|
810
|
-
} catch {}
|
|
811
|
-
|
|
812
|
-
// Package not installed — auto-install it
|
|
813
|
-
if (this._installCache.has(pkg)) {
|
|
814
|
-
throw new Error(`Package "${pkg}" could not be loaded after auto-install. Please install manually: npm install ${pkg}`);
|
|
815
|
-
}
|
|
816
|
-
this._installCache.add(pkg);
|
|
817
|
-
console.log(`[database-access] Auto-installing "${pkg}"...`);
|
|
818
|
-
const { execSync } = await import('child_process');
|
|
819
|
-
try {
|
|
820
|
-
execSync(`npm install --no-save ${pkg}`, {
|
|
821
|
-
stdio: 'pipe',
|
|
822
|
-
timeout: 120_000,
|
|
823
|
-
cwd: process.cwd(),
|
|
824
|
-
});
|
|
825
|
-
console.log(`[database-access] Successfully installed "${pkg}"`);
|
|
826
|
-
} catch (installErr: any) {
|
|
827
|
-
const msg = installErr.stderr?.toString?.().slice(0, 200) || installErr.message;
|
|
828
|
-
throw new Error(`Failed to auto-install "${pkg}": ${msg}. Please install manually: npm install ${pkg}`);
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
// Try all loading strategies again after install
|
|
832
|
-
const loaded = this._requirePkg(pkg);
|
|
833
|
-
if (loaded) return loaded;
|
|
834
|
-
|
|
835
|
-
// Final attempt with dynamic import
|
|
836
|
-
try {
|
|
837
|
-
return await import(pkg);
|
|
838
|
-
} catch {}
|
|
839
|
-
|
|
840
|
-
throw new Error(`Package "${pkg}" installed but could not be loaded. Try restarting the server, or install manually: npm install ${pkg}`);
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
/**
|
|
844
|
-
* Connect with a timeout wrapper — all drivers get a 15s connect timeout.
|
|
845
|
-
*/
|
|
846
|
-
private async connectWithTimeout<T>(fn: () => Promise<T>, timeoutMs = 15_000, label = 'Connection'): Promise<T> {
|
|
847
|
-
return new Promise<T>((resolve, reject) => {
|
|
848
|
-
const timer = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms — check your host/port and ensure the database is reachable`)), timeoutMs);
|
|
849
|
-
fn().then(
|
|
850
|
-
(v) => { clearTimeout(timer); resolve(v); },
|
|
851
|
-
(e) => { clearTimeout(timer); reject(e); },
|
|
852
|
-
);
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
/**
|
|
857
|
-
* Detect SSL requirement from connection string or cloud provider type.
|
|
858
|
-
* Cloud-hosted databases almost always require SSL.
|
|
859
|
-
*/
|
|
860
|
-
private needsSsl(config: any, credentials?: any): boolean | Record<string, any> {
|
|
861
|
-
if (config.ssl === true) return true;
|
|
862
|
-
if (config.ssl === false) return false;
|
|
863
|
-
// Auto-enable SSL for cloud providers
|
|
864
|
-
const cloudTypes: string[] = ['supabase', 'neon', 'planetscale', 'cockroachdb', 'turso', 'upstash'];
|
|
865
|
-
if (cloudTypes.includes(config.type)) return true;
|
|
866
|
-
// Detect from connection string
|
|
867
|
-
const connStr = credentials?.connectionString || '';
|
|
868
|
-
if (connStr.includes('sslmode=require') || connStr.includes('ssl=true')) return true;
|
|
869
|
-
// Supabase/Neon/etc URLs contain their domain
|
|
870
|
-
if (/supabase|neon\.tech|cockroachlabs|planetscale|turso\.io|railway\.app|render\.com|aiven\.io|timescale\.com/i.test(connStr)) return true;
|
|
871
|
-
if (/supabase|neon\.tech|cockroachlabs|planetscale|turso\.io|railway|render|aiven|timescale/i.test(config.host || '')) return true;
|
|
872
|
-
return false;
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
/**
|
|
876
|
-
* Parse a connection string to extract host/port/database/username when fields are missing.
|
|
877
|
-
*/
|
|
878
|
-
private parseConnectionString(connStr: string, _type: string): { host?: string; port?: number; database?: string; username?: string } {
|
|
879
|
-
try {
|
|
880
|
-
// Handle postgres://, mysql://, mongodb://, redis://, libsql:// etc
|
|
881
|
-
const cleaned = connStr.replace(/^(postgres|postgresql|mysql|mongodb\+srv|mongodb|redis|rediss|libsql)/, 'http');
|
|
882
|
-
const url = new URL(cleaned);
|
|
883
|
-
return {
|
|
884
|
-
host: url.hostname || undefined,
|
|
885
|
-
port: url.port ? parseInt(url.port) : undefined,
|
|
886
|
-
database: url.pathname?.replace(/^\//, '') || undefined,
|
|
887
|
-
username: url.username || undefined,
|
|
888
|
-
};
|
|
889
|
-
} catch {
|
|
890
|
-
return {};
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
private registerBuiltinDrivers(): void {
|
|
895
|
-
const self = this;
|
|
896
|
-
|
|
897
|
-
// ── PostgreSQL / CockroachDB / Supabase / Neon ─────────────────────────
|
|
898
|
-
const pgDriver: DatabaseDriver = {
|
|
899
|
-
async connect(config, credentials) {
|
|
900
|
-
const pgMod = await self.ensurePackage('postgres');
|
|
901
|
-
const pgFn = pgMod.default || pgMod;
|
|
902
|
-
|
|
903
|
-
// Build connection string from parts if not provided
|
|
904
|
-
let connStr = credentials.connectionString;
|
|
905
|
-
if (!connStr) {
|
|
906
|
-
const user = encodeURIComponent(config.username || 'postgres');
|
|
907
|
-
const pass = encodeURIComponent(credentials.password || '');
|
|
908
|
-
const host = config.host || 'localhost';
|
|
909
|
-
const port = config.port || 5432;
|
|
910
|
-
const db = config.database || 'postgres';
|
|
911
|
-
connStr = `postgresql://${user}:${pass}@${host}:${port}/${db}`;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
const ssl = self.needsSsl(config, credentials);
|
|
915
|
-
const sql: any = await self.connectWithTimeout(() => {
|
|
916
|
-
const s = pgFn(connStr, {
|
|
917
|
-
max: config.pool?.max ?? 10,
|
|
918
|
-
idle_timeout: (config.pool?.idleTimeoutMs ?? 30_000) / 1000,
|
|
919
|
-
connect_timeout: 10,
|
|
920
|
-
ssl: ssl ? (config.sslRejectUnauthorized === false ? 'prefer' as any : 'require' as any) : false,
|
|
921
|
-
});
|
|
922
|
-
// Force a connection attempt so errors surface now
|
|
923
|
-
return s`SELECT 1`.then(() => s);
|
|
924
|
-
}, 15_000, 'PostgreSQL');
|
|
925
|
-
|
|
926
|
-
return {
|
|
927
|
-
async query(q: string, params?: any[]) {
|
|
928
|
-
const result = params?.length ? await sql.unsafe(q, params) : await sql.unsafe(q);
|
|
929
|
-
return {
|
|
930
|
-
rows: [...result],
|
|
931
|
-
affectedRows: result.count,
|
|
932
|
-
fields: result.columns?.map((c: any) => ({ name: c.name, type: String(c.type) })),
|
|
933
|
-
};
|
|
934
|
-
},
|
|
935
|
-
async close() { try { await sql.end({ timeout: 5 }); } catch {} },
|
|
936
|
-
async ping() {
|
|
937
|
-
try { await sql`SELECT 1`; return true; }
|
|
938
|
-
catch (e: any) {
|
|
939
|
-
const msg = e instanceof AggregateError ? (e.errors?.map?.((x: any) => x.message).join('; ') || 'Multiple connection failures') : (e.message || String(e));
|
|
940
|
-
throw new Error('PostgreSQL ping failed: ' + msg);
|
|
941
|
-
}
|
|
942
|
-
},
|
|
943
|
-
};
|
|
944
|
-
},
|
|
945
|
-
};
|
|
946
|
-
this.drivers.set('postgresql', pgDriver);
|
|
947
|
-
this.drivers.set('cockroachdb', pgDriver);
|
|
948
|
-
this.drivers.set('supabase', pgDriver);
|
|
949
|
-
this.drivers.set('neon', pgDriver);
|
|
950
|
-
|
|
951
|
-
// ── MySQL / MariaDB / PlanetScale ──────────────────────────────────────
|
|
952
|
-
const mysqlDriver: DatabaseDriver = {
|
|
953
|
-
async connect(config, credentials) {
|
|
954
|
-
const mysql2 = await self.ensurePackage('mysql2/promise');
|
|
955
|
-
|
|
956
|
-
// Parse connection string for missing fields
|
|
957
|
-
const parsed = credentials.connectionString ? self.parseConnectionString(credentials.connectionString, config.type) : {};
|
|
958
|
-
const ssl = self.needsSsl(config, credentials);
|
|
959
|
-
|
|
960
|
-
const pool = await self.connectWithTimeout(async () => {
|
|
961
|
-
const p = mysql2.createPool({
|
|
962
|
-
host: config.host || parsed.host || 'localhost',
|
|
963
|
-
port: config.port || parsed.port || 3306,
|
|
964
|
-
user: config.username || parsed.username,
|
|
965
|
-
password: credentials.password || (credentials.connectionString ? (() => { try { const u = new URL(credentials.connectionString.replace(/^mysql/, 'http')); return decodeURIComponent(u.password); } catch { return undefined; } })() : undefined),
|
|
966
|
-
database: config.database || parsed.database,
|
|
967
|
-
connectionLimit: config.pool?.max ?? 10,
|
|
968
|
-
connectTimeout: 10_000,
|
|
969
|
-
ssl: ssl ? { rejectUnauthorized: config.sslRejectUnauthorized !== false } : undefined,
|
|
970
|
-
uri: credentials.connectionString || undefined,
|
|
971
|
-
});
|
|
972
|
-
// Validate connection
|
|
973
|
-
await p.execute('SELECT 1');
|
|
974
|
-
return p;
|
|
975
|
-
}, 15_000, 'MySQL');
|
|
976
|
-
|
|
977
|
-
return {
|
|
978
|
-
async query(q: string, params?: any[]) {
|
|
979
|
-
const [rows, fields] = await pool.execute(q, params);
|
|
980
|
-
const resultRows = Array.isArray(rows) ? rows : [];
|
|
981
|
-
return {
|
|
982
|
-
rows: resultRows as any[],
|
|
983
|
-
affectedRows: (rows as any).affectedRows,
|
|
984
|
-
fields: (fields as any[])?.map((f: any) => ({ name: f.name, type: String(f.type) })),
|
|
985
|
-
};
|
|
986
|
-
},
|
|
987
|
-
async close() { try { await pool.end(); } catch {} },
|
|
988
|
-
async ping() { try { await pool.execute('SELECT 1'); return true; } catch (e: any) { throw new Error('MySQL ping failed: ' + (e.message || e)); } },
|
|
989
|
-
};
|
|
990
|
-
},
|
|
991
|
-
};
|
|
992
|
-
this.drivers.set('mysql', mysqlDriver);
|
|
993
|
-
this.drivers.set('mariadb', mysqlDriver);
|
|
994
|
-
this.drivers.set('planetscale', mysqlDriver);
|
|
995
|
-
|
|
996
|
-
// ── SQLite ─────────────────────────────────────────────────────────────
|
|
997
|
-
this.drivers.set('sqlite', {
|
|
998
|
-
async connect(config, credentials) {
|
|
999
|
-
const sqliteMod = await self.ensurePackage('better-sqlite3');
|
|
1000
|
-
const Database = sqliteMod.default || sqliteMod;
|
|
1001
|
-
const dbPath = credentials.connectionString || config.database || ':memory:';
|
|
1002
|
-
const db = new Database(dbPath, { readonly: false });
|
|
1003
|
-
// Enable WAL mode for better concurrency
|
|
1004
|
-
try { db.pragma('journal_mode = WAL'); } catch {}
|
|
1005
|
-
return {
|
|
1006
|
-
async query(q: string, params?: any[]) {
|
|
1007
|
-
const trimmed = q.trim().toUpperCase();
|
|
1008
|
-
if (trimmed.startsWith('SELECT') || trimmed.startsWith('WITH') || trimmed.startsWith('PRAGMA') || trimmed.startsWith('EXPLAIN')) {
|
|
1009
|
-
const stmt = db.prepare(q);
|
|
1010
|
-
const rows = params?.length ? stmt.all(...params) : stmt.all();
|
|
1011
|
-
return { rows, fields: rows.length > 0 ? Object.keys(rows[0]).map(k => ({ name: k, type: 'unknown' })) : [] };
|
|
1012
|
-
} else {
|
|
1013
|
-
const stmt = db.prepare(q);
|
|
1014
|
-
const result = params?.length ? stmt.run(...params) : stmt.run();
|
|
1015
|
-
return { rows: [], affectedRows: result.changes };
|
|
1016
|
-
}
|
|
1017
|
-
},
|
|
1018
|
-
async close() { try { db.close(); } catch {} },
|
|
1019
|
-
async ping() { try { db.prepare('SELECT 1').get(); return true; } catch (e: any) { throw new Error('SQLite ping failed: ' + (e.message || e)); } },
|
|
1020
|
-
};
|
|
1021
|
-
},
|
|
1022
|
-
});
|
|
1023
|
-
|
|
1024
|
-
// ── Turso / LibSQL ─────────────────────────────────────────────────────
|
|
1025
|
-
this.drivers.set('turso', {
|
|
1026
|
-
async connect(config, credentials) {
|
|
1027
|
-
const libsql = await self.ensurePackage('@libsql/client');
|
|
1028
|
-
const { createClient } = libsql;
|
|
1029
|
-
|
|
1030
|
-
const url = credentials.connectionString || `libsql://${config.host}`;
|
|
1031
|
-
const client = createClient({ url, authToken: credentials.password });
|
|
1032
|
-
|
|
1033
|
-
// Validate
|
|
1034
|
-
await self.connectWithTimeout(() => client.execute('SELECT 1'), 15_000, 'Turso');
|
|
1035
|
-
|
|
1036
|
-
return {
|
|
1037
|
-
async query(q: string, params?: any[]) {
|
|
1038
|
-
const result = await client.execute({ sql: q, args: params || [] });
|
|
1039
|
-
return {
|
|
1040
|
-
rows: result.rows as any[],
|
|
1041
|
-
affectedRows: result.rowsAffected,
|
|
1042
|
-
fields: result.columns?.map((c: any) => ({ name: String(c), type: 'unknown' })),
|
|
1043
|
-
};
|
|
1044
|
-
},
|
|
1045
|
-
async close() { try { client.close(); } catch {} },
|
|
1046
|
-
async ping() { try { await client.execute('SELECT 1'); return true; } catch (e: any) { throw new Error('Turso ping failed: ' + (e.message || e)); } },
|
|
1047
|
-
};
|
|
1048
|
-
},
|
|
1049
|
-
});
|
|
1050
|
-
|
|
1051
|
-
// ── MongoDB ────────────────────────────────────────────────────────────
|
|
1052
|
-
this.drivers.set('mongodb', {
|
|
1053
|
-
async connect(config, credentials) {
|
|
1054
|
-
const mongoMod = await self.ensurePackage('mongodb');
|
|
1055
|
-
const { MongoClient } = mongoMod;
|
|
1056
|
-
|
|
1057
|
-
const uri = credentials.connectionString || (() => {
|
|
1058
|
-
const user = encodeURIComponent(config.username || '');
|
|
1059
|
-
const pass = encodeURIComponent(credentials.password || '');
|
|
1060
|
-
const host = config.host || 'localhost';
|
|
1061
|
-
const port = config.port || 27017;
|
|
1062
|
-
const db = config.database || 'admin';
|
|
1063
|
-
const auth = user ? `${user}:${pass}@` : '';
|
|
1064
|
-
return `mongodb://${auth}${host}:${port}/${db}`;
|
|
1065
|
-
})();
|
|
1066
|
-
|
|
1067
|
-
const ssl = self.needsSsl(config, credentials);
|
|
1068
|
-
// mongodb+srv:// always uses TLS
|
|
1069
|
-
const useTls = ssl || uri.startsWith('mongodb+srv://');
|
|
1070
|
-
|
|
1071
|
-
const client = new MongoClient(uri, {
|
|
1072
|
-
maxPoolSize: config.pool?.max ?? 10,
|
|
1073
|
-
serverSelectionTimeoutMS: 10_000,
|
|
1074
|
-
connectTimeoutMS: 10_000,
|
|
1075
|
-
tls: useTls || undefined,
|
|
1076
|
-
});
|
|
1077
|
-
|
|
1078
|
-
await self.connectWithTimeout(() => client.connect(), 15_000, 'MongoDB');
|
|
1079
|
-
const db = client.db(config.database || self.parseConnectionString(uri, 'mongodb').database);
|
|
1080
|
-
|
|
1081
|
-
return {
|
|
1082
|
-
async query(q: string, _params?: any[]) {
|
|
1083
|
-
try {
|
|
1084
|
-
const cmd = JSON.parse(q);
|
|
1085
|
-
const collection = db.collection(cmd.collection);
|
|
1086
|
-
switch (cmd.operation) {
|
|
1087
|
-
case 'find': {
|
|
1088
|
-
const cursor = collection.find(cmd.filter || {});
|
|
1089
|
-
if (cmd.projection) cursor.project(cmd.projection);
|
|
1090
|
-
if (cmd.sort) cursor.sort(cmd.sort);
|
|
1091
|
-
if (cmd.skip) cursor.skip(cmd.skip);
|
|
1092
|
-
cursor.limit(cmd.limit || 100);
|
|
1093
|
-
return { rows: await cursor.toArray() };
|
|
1094
|
-
}
|
|
1095
|
-
case 'findOne': {
|
|
1096
|
-
const doc = await collection.findOne(cmd.filter || {}, { projection: cmd.projection });
|
|
1097
|
-
return { rows: doc ? [doc] : [] };
|
|
1098
|
-
}
|
|
1099
|
-
case 'insertOne': {
|
|
1100
|
-
const r = await collection.insertOne(cmd.document);
|
|
1101
|
-
return { rows: [{ insertedId: r.insertedId }], affectedRows: 1 };
|
|
1102
|
-
}
|
|
1103
|
-
case 'insertMany': {
|
|
1104
|
-
const r = await collection.insertMany(cmd.documents);
|
|
1105
|
-
return { rows: [{ insertedCount: r.insertedCount }], affectedRows: r.insertedCount };
|
|
1106
|
-
}
|
|
1107
|
-
case 'updateOne': case 'updateMany': {
|
|
1108
|
-
const fn = cmd.operation === 'updateOne' ? collection.updateOne.bind(collection) : collection.updateMany.bind(collection);
|
|
1109
|
-
const r = await fn(cmd.filter || {}, cmd.update, { upsert: cmd.upsert });
|
|
1110
|
-
return { rows: [{ matchedCount: r.matchedCount, modifiedCount: r.modifiedCount, upsertedId: r.upsertedId }], affectedRows: r.modifiedCount };
|
|
1111
|
-
}
|
|
1112
|
-
case 'deleteOne': case 'deleteMany': {
|
|
1113
|
-
const fn = cmd.operation === 'deleteOne' ? collection.deleteOne.bind(collection) : collection.deleteMany.bind(collection);
|
|
1114
|
-
const r = await fn(cmd.filter || {});
|
|
1115
|
-
return { rows: [], affectedRows: r.deletedCount };
|
|
1116
|
-
}
|
|
1117
|
-
case 'aggregate': return { rows: await collection.aggregate(cmd.pipeline || []).toArray() };
|
|
1118
|
-
case 'count': case 'countDocuments': return { rows: [{ count: await collection.countDocuments(cmd.filter || {}) }] };
|
|
1119
|
-
case 'distinct': return { rows: [{ values: await collection.distinct(cmd.field, cmd.filter || {}) }] };
|
|
1120
|
-
case 'listCollections': {
|
|
1121
|
-
const cols = await db.listCollections().toArray();
|
|
1122
|
-
return { rows: cols.map((c: any) => ({ name: c.name, type: c.type })) };
|
|
1123
|
-
}
|
|
1124
|
-
default: throw new Error(`Unknown operation: ${cmd.operation}. Supported: find, findOne, insertOne, insertMany, updateOne, updateMany, deleteOne, deleteMany, aggregate, count, distinct, listCollections`);
|
|
1125
|
-
}
|
|
1126
|
-
} catch (err: any) {
|
|
1127
|
-
throw new Error(`MongoDB query error: ${err.message}`);
|
|
1128
|
-
}
|
|
1129
|
-
},
|
|
1130
|
-
async close() { try { await client.close(); } catch {} },
|
|
1131
|
-
async ping() { try { await db.command({ ping: 1 }); return true; } catch (e: any) { throw new Error('MongoDB ping failed: ' + (e.message || e)); } },
|
|
1132
|
-
};
|
|
1133
|
-
},
|
|
1134
|
-
});
|
|
1135
|
-
|
|
1136
|
-
// ── Redis (self-hosted or cloud with standard Redis protocol) ──────────
|
|
1137
|
-
this.drivers.set('redis', {
|
|
1138
|
-
async connect(config, credentials) {
|
|
1139
|
-
const host = config.host || 'localhost';
|
|
1140
|
-
const port = config.port || 6379;
|
|
1141
|
-
const ssl = self.needsSsl(config, credentials);
|
|
1142
|
-
const connStr = credentials.connectionString || '';
|
|
1143
|
-
|
|
1144
|
-
// Detect if connection string uses rediss:// (TLS)
|
|
1145
|
-
const useTls = ssl || connStr.startsWith('rediss://');
|
|
1146
|
-
|
|
1147
|
-
// Parse auth from connection string if present
|
|
1148
|
-
let password = credentials.password;
|
|
1149
|
-
let username = config.username;
|
|
1150
|
-
if (connStr) {
|
|
1151
|
-
try {
|
|
1152
|
-
const _parsed = self.parseConnectionString(connStr, 'redis');
|
|
1153
|
-
if (!password) {
|
|
1154
|
-
// redis://user:pass@host:port or redis://:pass@host:port
|
|
1155
|
-
const url = new URL(connStr.replace(/^redis(s?)/, 'http'));
|
|
1156
|
-
password = url.password || password;
|
|
1157
|
-
username = url.username || username;
|
|
1158
|
-
}
|
|
1159
|
-
} catch {}
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
// Use TLS or plain net socket
|
|
1163
|
-
let socket: any;
|
|
1164
|
-
const connectHost = connStr ? (self.parseConnectionString(connStr, 'redis').host || host) : host;
|
|
1165
|
-
const connectPort = connStr ? (self.parseConnectionString(connStr, 'redis').port || port) : port;
|
|
1166
|
-
|
|
1167
|
-
await self.connectWithTimeout(async () => {
|
|
1168
|
-
if (useTls) {
|
|
1169
|
-
const tls = await import('tls');
|
|
1170
|
-
socket = tls.connect({ host: connectHost, port: connectPort, rejectUnauthorized: config.sslRejectUnauthorized !== false });
|
|
1171
|
-
await new Promise<void>((resolve, reject) => {
|
|
1172
|
-
socket.on('secureConnect', resolve);
|
|
1173
|
-
socket.on('error', reject);
|
|
1174
|
-
});
|
|
1175
|
-
} else {
|
|
1176
|
-
const net = await import('net');
|
|
1177
|
-
socket = new net.Socket();
|
|
1178
|
-
await new Promise<void>((resolve, reject) => {
|
|
1179
|
-
socket.connect(connectPort, connectHost, () => resolve());
|
|
1180
|
-
socket.on('error', reject);
|
|
1181
|
-
});
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
// AUTH if needed — support Redis 6+ ACL: AUTH username password
|
|
1185
|
-
if (password) {
|
|
1186
|
-
const authCmd = username && username !== 'default' ? `AUTH ${username} ${password}` : `AUTH ${password}`;
|
|
1187
|
-
await sendRedisCommand(socket, authCmd);
|
|
1188
|
-
}
|
|
1189
|
-
}, 15_000, 'Redis');
|
|
1190
|
-
|
|
1191
|
-
function sendRedisCommand(sock: any, cmd: string): Promise<string> {
|
|
1192
|
-
return new Promise((resolve, reject) => {
|
|
1193
|
-
let data = '';
|
|
1194
|
-
const onData = (chunk: Buffer) => { data += chunk.toString(); if (data.includes('\r\n')) { sock.off('data', onData); resolve(data); } };
|
|
1195
|
-
sock.on('data', onData);
|
|
1196
|
-
sock.write(cmd + '\r\n');
|
|
1197
|
-
setTimeout(() => { sock.off('data', onData); reject(new Error('Redis command timed out after 10s')); }, 10_000);
|
|
1198
|
-
});
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
return {
|
|
1202
|
-
async query(q: string) {
|
|
1203
|
-
const result = await sendRedisCommand(socket, q);
|
|
1204
|
-
return { rows: [{ result: result.trim() }] };
|
|
1205
|
-
},
|
|
1206
|
-
async close() { try { socket.destroy(); } catch {} },
|
|
1207
|
-
async ping() { try { const r = await sendRedisCommand(socket, 'PING'); if (!r.includes('PONG')) throw new Error('No PONG response'); return true; } catch (e: any) { throw new Error('Redis ping failed: ' + (e.message || e)); } },
|
|
1208
|
-
};
|
|
1209
|
-
},
|
|
1210
|
-
});
|
|
1211
|
-
|
|
1212
|
-
// ── Upstash Redis (REST API — zero dependencies) ──────────────────────
|
|
1213
|
-
this.drivers.set('upstash', {
|
|
1214
|
-
async connect(config, credentials) {
|
|
1215
|
-
// Upstash REST: https://<endpoint>.upstash.io with Bearer token
|
|
1216
|
-
// Connection string format: https://<token>@<endpoint>.upstash.io or just the URL
|
|
1217
|
-
let baseUrl = '';
|
|
1218
|
-
let token = credentials.password || '';
|
|
1219
|
-
|
|
1220
|
-
if (credentials.connectionString) {
|
|
1221
|
-
const cs = credentials.connectionString;
|
|
1222
|
-
// Handle https://token@host format
|
|
1223
|
-
if (cs.startsWith('https://') && cs.includes('@')) {
|
|
1224
|
-
try {
|
|
1225
|
-
const url = new URL(cs);
|
|
1226
|
-
token = token || url.username || url.password;
|
|
1227
|
-
baseUrl = `https://${url.host}`;
|
|
1228
|
-
} catch {
|
|
1229
|
-
baseUrl = cs;
|
|
1230
|
-
}
|
|
1231
|
-
} else if (cs.startsWith('https://')) {
|
|
1232
|
-
baseUrl = cs.replace(/\/$/, '');
|
|
1233
|
-
} else if (cs.startsWith('rediss://')) {
|
|
1234
|
-
// Upstash also provides redis:// URLs — extract host for REST
|
|
1235
|
-
try {
|
|
1236
|
-
const url = new URL(cs.replace('rediss://', 'https://'));
|
|
1237
|
-
token = token || url.password;
|
|
1238
|
-
baseUrl = `https://${url.hostname}`;
|
|
1239
|
-
} catch {
|
|
1240
|
-
baseUrl = `https://${config.host}`;
|
|
1241
|
-
}
|
|
1242
|
-
} else {
|
|
1243
|
-
baseUrl = `https://${cs}`;
|
|
1244
|
-
}
|
|
1245
|
-
} else {
|
|
1246
|
-
baseUrl = `https://${config.host}`;
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
if (!baseUrl) throw new Error('Upstash requires a REST URL or hostname. Find it in your Upstash console under REST API.');
|
|
1250
|
-
if (!token) throw new Error('Upstash requires an auth token. Find it in your Upstash console under REST API.');
|
|
1251
|
-
|
|
1252
|
-
async function upstashRequest(command: string[]): Promise<any> {
|
|
1253
|
-
const ctrl = new AbortController();
|
|
1254
|
-
const timer = setTimeout(() => ctrl.abort(), 10_000);
|
|
1255
|
-
try {
|
|
1256
|
-
const resp = await fetch(baseUrl, {
|
|
1257
|
-
method: 'POST',
|
|
1258
|
-
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
1259
|
-
body: JSON.stringify(command),
|
|
1260
|
-
signal: ctrl.signal,
|
|
1261
|
-
});
|
|
1262
|
-
if (!resp.ok) {
|
|
1263
|
-
const body = await resp.text().catch(() => '');
|
|
1264
|
-
throw new Error(`Upstash HTTP ${resp.status}: ${body.slice(0, 200)}`);
|
|
1265
|
-
}
|
|
1266
|
-
return resp.json();
|
|
1267
|
-
} finally {
|
|
1268
|
-
clearTimeout(timer);
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
// Validate connection
|
|
1273
|
-
await self.connectWithTimeout(async () => {
|
|
1274
|
-
const r = await upstashRequest(['PING']);
|
|
1275
|
-
if (r.result !== 'PONG') throw new Error('Upstash PING failed — check your token and endpoint URL');
|
|
1276
|
-
}, 15_000, 'Upstash');
|
|
1277
|
-
|
|
1278
|
-
return {
|
|
1279
|
-
async query(q: string) {
|
|
1280
|
-
const parts = q.trim().split(/\s+/);
|
|
1281
|
-
const result = await upstashRequest(parts);
|
|
1282
|
-
const val = result.result ?? result;
|
|
1283
|
-
return { rows: [{ result: typeof val === 'string' ? val : JSON.stringify(val) }] };
|
|
1284
|
-
},
|
|
1285
|
-
async close() { /* stateless REST — nothing to close */ },
|
|
1286
|
-
async ping() { try { const r = await upstashRequest(['PING']); if (r.result !== 'PONG') throw new Error('No PONG response'); return true; } catch (e: any) { throw new Error('Upstash ping failed: ' + (e.message || e)); } },
|
|
1287
|
-
};
|
|
1288
|
-
},
|
|
1289
|
-
});
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
// ─── Row Mapping ───────────────────────────────────────────────────────────
|
|
1293
|
-
|
|
1294
|
-
private rowToConfig(row: any): DatabaseConnectionConfig {
|
|
1295
|
-
const config = typeof row.config === 'string' ? JSON.parse(row.config) : (row.config || {});
|
|
1296
|
-
return {
|
|
1297
|
-
id: row.id,
|
|
1298
|
-
orgId: row.org_id,
|
|
1299
|
-
name: row.name,
|
|
1300
|
-
type: row.type,
|
|
1301
|
-
...config,
|
|
1302
|
-
status: row.status,
|
|
1303
|
-
lastTestedAt: row.last_tested_at,
|
|
1304
|
-
lastError: row.last_error,
|
|
1305
|
-
createdAt: row.created_at,
|
|
1306
|
-
updatedAt: row.updated_at,
|
|
1307
|
-
};
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
private rowToAccess(row: any): AgentDatabaseAccess {
|
|
1311
|
-
return {
|
|
1312
|
-
id: row.id,
|
|
1313
|
-
orgId: row.org_id,
|
|
1314
|
-
agentId: row.agent_id,
|
|
1315
|
-
connectionId: row.connection_id,
|
|
1316
|
-
permissions: typeof row.permissions === 'string' ? JSON.parse(row.permissions) : (row.permissions || ['read']),
|
|
1317
|
-
queryLimits: typeof row.query_limits === 'string' ? JSON.parse(row.query_limits) : row.query_limits,
|
|
1318
|
-
schemaAccess: typeof row.schema_access === 'string' ? JSON.parse(row.schema_access) : row.schema_access,
|
|
1319
|
-
logAllQueries: !!row.log_all_queries,
|
|
1320
|
-
requireApproval: !!row.require_approval,
|
|
1321
|
-
enabled: !!row.enabled,
|
|
1322
|
-
createdAt: row.created_at,
|
|
1323
|
-
updatedAt: row.updated_at,
|
|
1324
|
-
};
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
private configToStorable(config: DatabaseConnectionConfig): Record<string, any> {
|
|
1328
|
-
// Strip fields stored in their own columns
|
|
1329
|
-
const { id, orgId, name, type, status, lastTestedAt, lastError, createdAt, updatedAt, ...rest } = config;
|
|
1330
|
-
return rest;
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
// ─── Cleanup ───────────────────────────────────────────────────────────────
|
|
1334
|
-
|
|
1335
|
-
async shutdown(): Promise<void> {
|
|
1336
|
-
for (const [connId] of this.pools) {
|
|
1337
|
-
await this.closePool(connId);
|
|
1338
|
-
}
|
|
1339
|
-
console.log('[db-access] All connection pools closed');
|
|
1340
|
-
}
|
|
1341
|
-
}
|