Skip to content

Commit e9ee351

Browse files
authored
v0.6.88: mutex lock on oauth refresh, files export fix, hubspot trigger, search & replace UX, kb connectors multi-select, mcp negative cache
2 parents fde70e2 + 3d9a1c4 commit e9ee351

159 files changed

Lines changed: 8104 additions & 9389 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/docs/content/docs/en/self-hosting/environment-variables.mdx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,48 @@ import { Callout } from 'fumadocs-ui/components/callout'
6666
| `API_ENCRYPTION_KEY` | Encrypts stored API keys (32 hex chars): `openssl rand -hex 32` |
6767
| `COPILOT_API_KEY` | API key for copilot features |
6868
| `ADMIN_API_KEY` | Admin API key for GitOps operations |
69-
| `RESEND_API_KEY` | Email service for notifications |
7069
| `ALLOWED_LOGIN_DOMAINS` | Restrict signups to domains (comma-separated) |
7170
| `ALLOWED_LOGIN_EMAILS` | Restrict signups to specific emails (comma-separated) |
7271
| `DISABLE_REGISTRATION` | Set to `true` to disable new user signups |
7372

73+
## Email Providers
74+
75+
Configure one provider — the mailer auto-detects in priority order: **Resend → AWS SES → SMTP → Azure Communication Services**. If none are configured, emails are logged to the console instead.
76+
77+
| Variable | Description |
78+
|----------|-------------|
79+
| `FROM_EMAIL_ADDRESS` | Sender address (e.g. `Sim <noreply@example.com>`). Falls back to `noreply@EMAIL_DOMAIN`. |
80+
| `EMAIL_DOMAIN` | Default domain when `FROM_EMAIL_ADDRESS` is unset |
81+
| `EMAIL_VERIFICATION_ENABLED` | Set to `true` to require email verification on signup |
82+
83+
**Resend**
84+
85+
| Variable | Description |
86+
|----------|-------------|
87+
| `RESEND_API_KEY` | API key from [resend.com](https://resend.com) |
88+
89+
**AWS SES**
90+
91+
| Variable | Description |
92+
|----------|-------------|
93+
| `AWS_SES_REGION` | AWS region for SES (e.g. `us-east-1`). Credentials are resolved through the standard AWS SDK provider chain (env vars, IRSA, ECS/EC2 instance role, SSO). |
94+
95+
**SMTP** (works with MailHog, Postfix, SendGrid SMTP, etc.)
96+
97+
| Variable | Description |
98+
|----------|-------------|
99+
| `SMTP_HOST` | SMTP server hostname |
100+
| `SMTP_PORT` | `465` for implicit TLS, `587` for STARTTLS, `25` for plain |
101+
| `SMTP_USER` | Optional — omit for unauthenticated relays |
102+
| `SMTP_PASS` | Optional — omit for unauthenticated relays |
103+
| `SMTP_SECURE` | Set to `true` to force TLS on connect; auto-true on port 465 |
104+
105+
**Azure Communication Services**
106+
107+
| Variable | Description |
108+
|----------|-------------|
109+
| `AZURE_ACS_CONNECTION_STRING` | Azure Communication Services connection string |
110+
74111
## Example .env
75112

76113
```bash

apps/docs/content/docs/en/triggers/hubspot.mdx

Lines changed: 22 additions & 1117 deletions
Large diffs are not rendered by default.

apps/sim/.env.example

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,30 @@ INTERNAL_API_SECRET=your_internal_api_secret # Use `openssl rand -hex 32` to gen
1919
API_ENCRYPTION_KEY=your_api_encryption_key # Use `openssl rand -hex 32` to generate, used to encrypt api keys
2020

2121
# Email Provider (Optional)
22-
# RESEND_API_KEY= # Uncomment and add your key from https://resend.com to send actual emails
23-
# If left commented out, emails will be logged to console instead
22+
# Configure ONE provider — the mailer auto-detects in priority order:
23+
# Resend → AWS SES → SMTP → Azure Communication Services. If none are
24+
# configured, emails are logged to console instead.
25+
#
26+
# Resend
27+
# RESEND_API_KEY= # API key from https://resend.com
28+
#
29+
# AWS SES (credentials resolved via the standard AWS provider chain:
30+
# env vars, shared config, ECS/EKS task role, EC2 instance profile, SSO)
31+
# AWS_SES_REGION=us-east-1
32+
#
33+
# SMTP (works with MailHog locally: host=localhost port=1025, no auth)
34+
# SMTP_HOST=smtp.example.com
35+
# SMTP_PORT=587 # 465 = implicit TLS, 587 = STARTTLS, 25 = plain
36+
# SMTP_USER= # Optional — omit for unauthenticated relays
37+
# SMTP_PASS= # Optional — omit for unauthenticated relays
38+
# SMTP_SECURE= # Set "true" to force TLS on connect; auto-true on port 465
39+
#
40+
# Azure Communication Services
41+
# AZURE_ACS_CONNECTION_STRING=
42+
#
43+
# Shared sender configuration
44+
# FROM_EMAIL_ADDRESS="Sim <noreply@example.com>"
45+
# EMAIL_DOMAIN=example.com # Fallback when FROM_EMAIL_ADDRESS is unset
2446

2547
# Local AI Models (Optional)
2648
# OLLAMA_URL=http://localhost:11434 # URL for local Ollama server - uncomment if using local models

apps/sim/app/api/auth/oauth/utils.test.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
* @vitest-environment node
55
*/
66

7+
import { redisConfigMock, redisConfigMockFns } from '@sim/testing'
78
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
89

910
vi.mock('@/lib/oauth/oauth', () => ({
1011
refreshOAuthToken: vi.fn(),
1112
OAUTH_PROVIDERS: {},
1213
}))
1314

15+
vi.mock('@/lib/core/config/redis', () => redisConfigMock)
16+
1417
import { db } from '@sim/db'
18+
import { __resetCoalesceLocallyForTests } from '@/lib/concurrency/singleflight'
1519
import { refreshOAuthToken } from '@/lib/oauth'
1620
import {
1721
getCredential,
@@ -49,6 +53,10 @@ function mockUpdateChain() {
4953
describe('OAuth Utils', () => {
5054
beforeEach(() => {
5155
vi.clearAllMocks()
56+
__resetCoalesceLocallyForTests()
57+
redisConfigMockFns.mockGetRedisClient.mockReturnValue(null)
58+
redisConfigMockFns.mockAcquireLock.mockResolvedValue(true)
59+
redisConfigMockFns.mockReleaseLock.mockResolvedValue(true)
5260
})
5361

5462
afterEach(() => {
@@ -107,6 +115,7 @@ describe('OAuth Utils', () => {
107115
}
108116

109117
mockRefreshOAuthToken.mockResolvedValueOnce({
118+
ok: true,
110119
accessToken: 'new-token',
111120
expiresIn: 3600,
112121
refreshToken: 'new-refresh-token',
@@ -130,7 +139,11 @@ describe('OAuth Utils', () => {
130139
providerId: 'google',
131140
}
132141

133-
mockRefreshOAuthToken.mockResolvedValueOnce(null)
142+
mockRefreshOAuthToken.mockResolvedValueOnce({
143+
ok: false,
144+
errorCode: 'invalid_grant',
145+
message: 'Failed',
146+
})
134147

135148
await expect(
136149
refreshTokenIfNeeded('request-id', mockCredential, 'credential-id')
@@ -198,6 +211,7 @@ describe('OAuth Utils', () => {
198211
mockUpdateChain()
199212

200213
mockRefreshOAuthToken.mockResolvedValueOnce({
214+
ok: true,
201215
accessToken: 'new-token',
202216
expiresIn: 3600,
203217
refreshToken: 'new-refresh-token',
@@ -237,7 +251,11 @@ describe('OAuth Utils', () => {
237251
mockSelectChain([mockResolvedCredential])
238252
mockSelectChain([mockAccountRow])
239253

240-
mockRefreshOAuthToken.mockResolvedValueOnce(null)
254+
mockRefreshOAuthToken.mockResolvedValueOnce({
255+
ok: false,
256+
errorCode: 'invalid_grant',
257+
message: 'Failed',
258+
})
241259

242260
const token = await refreshAccessTokenIfNeeded('credential-id', 'test-user-id', 'request-id')
243261

0 commit comments

Comments
 (0)