Commit Graph

488 Commits

Author SHA1 Message Date
KM Koushik 2eca312022 fix: resolve dependabot security alerts (#404) 2026-05-18 14:53:02 +10:00
KM Koushik aa7c234284 chore: remove Claude workflows (#403)
* fix: update Claude workflows

Entire-Checkpoint: ece952fb64ea

* chore: remove Claude workflows

Entire-Checkpoint: 3b66c252f834
2026-05-18 13:26:45 +10:00
KM Koushik dad2941971 chore: add Entire agent config (#402)
Entire-Checkpoint: 69bf47d06770
2026-05-18 10:38:23 +10:00
KM Koushik 04d0f4b123 feat: support standard AWS env vars and default credential chain (#401)
* feat: support standard AWS env vars and default credential chain

Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.

Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.

Closes #316

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* refactor: extract shared getAwsCredentialOptions helper and add partial-config guard

- Move the credential spread logic into a single credentials.ts helper
  so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
  is set, preventing silent fallback to the default provider chain with a
  half-configured environment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: align AWS env vars in docker and docs

* fix: use alias import for AWS credentials helper

---------

Co-authored-by: purva <purvahk08@gmail.com>
Co-authored-by: Purva Kandalgaonkar <136103488+purva-8@users.noreply.github.com>
2026-05-17 21:23:28 +10:00
Benoît 31a49fbdca Fix: Campaign subject is now interpolated with contact variables (#397)
* fix(campaign): fixed variables replacement in mail subjects

* improvement(tests): added test cases and respect conventionnal imports
2026-05-17 06:42:21 +10:00
Rohan Kumar 964bbf96dc fix: correct metadata description typo (#393) 2026-05-02 14:20:03 +10:00
Jothiprakash T 5b9788eb3d Fix/domain regex validation (#384)
* fix: add regex validation for domain field in waitlist form

* chore: revert unintended change in marketing page
2026-04-13 06:48:37 +10:00
João Nuno c2f17f012b fix: configure GitHub OAuth issuer (#388)
* fix: configure github oauth issuer

* fix: set cloud-mode flag in test env mock

* test: stabilize auth issuer unit test
2026-04-13 06:47:31 +10:00
KM Koushik b20f3b5d74 fix: keep paid limits during Stripe retries (#386) 2026-04-01 13:37:09 +11:00
KM Koushik bd78ed9ad9 feat: add Sayr bronze sponsor (#383)
* feat: add Sayr bronze sponsor

* fix: correct Sayr black logo URL

* update ui
2026-03-28 08:57:51 +11:00
KM Koushik eafbb53104 docs: add v1.9.x changelog entry (#382)
* docs: add v1.9.x highlights to changelog

* docs: refine v1.9.0 changelog entry

* docs: expand v1.9.0 changelog copy
2026-03-23 15:55:04 +11:00
KM Koushik 741b2b159f fix: restore centered dialog fade animation after tailwind v4 migration (#381) 2026-03-16 22:30:07 +11:00
KM Koushik b16eb201d2 Add 'tebayoso' profile link and image to README
Added a link and image for the user 'tebayoso' to the README.
2026-03-16 22:20:59 +11:00
KM Koushik da9d5acdb4 Update README to reflect webhook support status 2026-03-16 22:18:07 +11:00
KM Koushik 42e68bfc49 fix: type dashboard chart metric keys (#380) 2026-03-16 00:07:28 +11:00
KM Koushik 4307670822 feat: better dashboard chart (#378)
* dashbaord ui stuff

* graph stuff

* stuff
2026-03-15 18:28:17 +11:00
KM Koushik 9a306b1d59 feat: migrate workspace to Tailwind CSS v4 (#377)
* feat: migrate workspace to Tailwind CSS v4

* refactor: move Tailwind v4 setup to CSS directives
2026-03-15 07:10:37 +11:00
KM Koushik d7b196c0e3 fix: simplify domain verification emails (#376) 2026-03-14 08:22:16 +11:00
KM Koushik 689cb8b366 feat: automate domain verification follow-ups (#375)
* feat: automate domain verification follow-ups

* fix: harden domain verification notifications

* fix: skip unchanged first-run domain status emails

* fix: make domain cleanup resilient and status labels readable

* fix: clarify domain verification notification messaging
2026-03-14 01:19:44 +11:00
KM Koushik 3c2d37906e feat: add multi-domain filters to webhooks (#361)
* feat(webhooks): add multi-domain endpoint filtering

* test(webhooks): add domain filter router coverage

* fix(webhooks): apply domain filters only to domain-scoped events

* stuff

* stuff
2026-03-08 09:01:39 +11:00
KM Koushik 79f9049e40 docs: add campaign personalization guide (#374)
* docs: add campaign personalization guide

* docs: show best practices without accordions
2026-03-08 08:23:37 +11:00
KM Koushik 83cb0b24f7 feat: sync sdk contact book support (#373) 2026-03-08 00:59:40 +11:00
KM Koushik 33acd09d77 fix build 2026-03-08 00:15:34 +11:00
KM Koushik 62e0a1db88 feat: add contact-book variable registry for campaign personalization (#359)
* feat: add contact-book variable registry for campaign personalization

* test: include contact-book variables default in service expectation

* fix: address personalization review issues

* fix text

* fix: normalize contact variable access across contact flows

* stuff

* fix
2026-03-08 00:03:58 +11:00
KM Koushik d97e445ea0 fix: bump usesend-js version to 1.6.2 for npm publish (#372) 2026-03-04 22:09:58 +11:00
Dave Stockley ce8b780155 feat: add dashboard analytics to sdk and public api (#353) 2026-03-04 22:06:21 +11:00
KM Koushik 991fcab764 fix: bump usesend-js version to 1.6.1 for npm publish (#371) 2026-03-04 09:52:43 +11:00
Dave Stockley 7428a1fbfa feat: add contactBooks to sdk, add delete campaign public endpoint (#352)
* feat: add contactBooks to sdk, add delete campaign public endpoint

* fix: pr review notes

* refactor: pr feedback

* feat: bulk delete/create contacts

* refactor: rename a few methods for consistency

* refactor: update openapi docs based on pr feedback

* refactor: update open api docs, based on pr feedback

* fix: delete campaign security issue

* refactor: delete campaign requires team id (from context)

* fix: enums
2026-03-04 07:10:43 +11:00
KM Koushik 73416dc481 fix(test): add redisKey to Redis mocks (#369)
* fix(test): mock redisKey in Redis test doubles

* fix(test): include BULL_PREFIX in redis mock
2026-03-02 08:43:29 +11:00
Michał Ordon 62d7c44efc feat: add REDIS_KEY_PREFIX env var for Redis ACL namespace isolation (#365)
* feat: add REDIS_KEY_PREFIX env var for Redis ACL namespace isolation

Adds optional REDIS_KEY_PREFIX env var that prefixes all Redis keys
(BullMQ queues via `prefix` option, cache/lock/rate-limit keys via
`redisKey()` helper). When unset, behavior is unchanged (BullMQ
defaults to "bull:", cache keys are unprefixed).

This enables self-hosters using Redis ACL multi-tenancy to restrict
useSend to its own key namespace (e.g. `~usesend:*`).

16 files changed across env schema, Redis module, 9 BullMQ queue/worker
files, and 5 direct Redis key operation sites.

* docs: add REDIS_KEY_PREFIX to self-host assets and fix docker run example

Add REDIS_KEY_PREFIX env var to docker/prod/compose.yml, .env.example,
.env.selfhost.example, and self-hosting docs. Fix missing trailing
backslashes in standalone docker run example.

* fix(redis): disable ioredis ready check and BullMQ version check

Redis ACL blocks INFO command (in @dangerous category). ioredis uses
INFO for ready check, BullMQ uses it for version detection. Without
these flags, BullMQ workers fail to initialize and silently stop
processing jobs.

- Add enableReadyCheck: false to ioredis connection
- Add skipVersionCheck: true to all 5 Queue + 5 Worker constructors

* fix(redis): add skipVersionCheck to remaining BullMQ job queues

Add skipVersionCheck: true to Queue and Worker constructors in all 4 job
files (campaign-scheduler, cleanup-email-bodies, usage-job,
webhook-cleanup) to match the pattern already used in service files.
This prevents BullMQ version mismatch errors when using REDIS_KEY_PREFIX
with Redis ACL namespace isolation.
2026-03-02 08:12:47 +11:00
KM Koushik 69eeb2d96e fix: reset contact list page when filters change (#368) 2026-03-01 20:38:42 +11:00
Anish de9bbcdc00 Fix typo in double-opt-in confirmation message (#367) 2026-03-01 10:45:48 +11:00
KM Koushik 9e588e2e6b feat: submit contact add form with Cmd/Ctrl+Enter (#366) 2026-03-01 00:58:02 +11:00
KM Koushik e3e9635a5f feat: add customizable contact double opt-in flow (#350)
* feat: add customizable contact double opt-in flow

* test: add double opt-in service coverage

* fix: address review comments for double opt-in PR

- Make pending status conditional on doubleOptInEnabled flag
- Backfill legacy unsubscribeReason for reliable pending detection
- Add doubleOptInContent to contact book listing select
- Fix duplicate toast on DOI editor subject save failure
- Harden searchParams parsing against string[] values
- Make default DOI template use link mark for clickable URL
- Make public API create+update atomic via transaction
- Prevent contact upsert failure when DOI email send fails
- Fix empty string template variable replacement

Co-authored-by: opencode <opencode@anthropic.com>

* fix: harden double opt-in confirmation safeguards

Preserve explicit unsubscribe intent in DOI flows and prevent confirmation links from re-subscribing opted-out contacts. Also sanitize subscribe-page error messaging and use timing-safe hash comparison for link verification.

* ui stuff

* fix: require doubleOptInUrl in double opt-in templates

* feat: add configurable from address for double opt-in emails

* feat: add resend confirmation flow for pending contacts

* fix: move subscribe confirmation to explicit POST flow

* test: add contact book public API endpoint coverage

* docs: add double opt-in documentation and update OpenAPI spec

Add a user guide for the double opt-in feature covering setup, contact
statuses, email customization, template variables, and best practices.
Update the OpenAPI spec to include doubleOptIn fields in all contactBook
request/response schemas.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: opencode <opencode@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:34:20 +11:00
KM Koushik edcd32a4ea fix: prevent premature webhook auto-disable and allow re-enable (#364)
* fix: prevent premature webhook auto-disable and allow re-enable

Use persisted failure counters when deciding auto-disable status and restore dashboard re-enable flow so webhooks are not deactivated unexpectedly after reset.

* fix: count webhook failures per failed call

Only increment consecutive failure counters after a call exhausts retries, while keeping the 30-call auto-disable threshold and stale-state protection.

* fix(docs): correct webhook SDK package name (#363)

* test: isolate webhook unit suite from mailer deps

Mock limit service in webhook unit tests so Vitest does not resolve team-service and mailer paths requiring usesend-js during CI.
2026-02-28 07:40:26 +11:00
KM Koushik 1c644740f2 fix(docs): correct webhook SDK package name (#363) 2026-02-28 07:15:04 +11:00
Dan b2ed09e7a7 feat: add API key editing functionality to the dashboard (#358)
- new edit button in /dev-settings
- new updateApiKey mutation in api router
- new edit dialog-component
- new update-function in api-service
- changed sorting of api-key query to avoid list items jumping after updates
2026-02-25 23:11:11 +11:00
KM Koushik 0c9ebc86a3 fix: preserve reply-to metadata when duplicating campaigns (#357) 2026-02-23 12:06:33 +11:00
KM Koushik 61dfcee67d fix: enforce team scoping for campaign, contacts, and invites (#356)
* fix: enforce team-scoped lookups for campaign contacts and invites

* fix(test): mock domain service in campaign security test
2026-02-23 11:30:05 +11:00
KM Koushik f7a0d11758 Fix webhook documentation link in changelog
Updated webhook documentation link to point to the correct URL.
2026-02-22 23:28:15 +11:00
KM Koushik 091b99cb10 Add v1.8.0 changelog entry with February 2025 updates (#348)
* docs: add v1.8.0 changelog with features since v1.7.0

Adds changelog entry covering webhooks, Python SDK, Contact Books API,
email retention/cleanup, idempotency support, and various improvements.

https://claude.ai/code/session_012hGggJSKqRZB4PkaaPAyrS

* update

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-22 22:19:41 +11:00
Manoj Naik 585cd23ba2 fix: sync suppression list removal with AWS SES (closes #324) (#331)
* fix: sync suppression list removal with AWS SES (closes #324)

When removing an email from the suppression list, now also removes it from
AWS SES account-level suppression list across all regions where the team
has domains configured.

- Add deleteFromSesSuppressionList helper to ses.ts
- Update removeSuppression to query team domains for unique regions
- Use best-effort pattern: AWS failures don't block local DB deletion
- Handle NotFoundException gracefully (email not in SES list)

* fix: correct failure detection logic for SES suppression removal

deleteFromSesSuppressionList returns false on error (never throws),
so check for fulfilled promises with value === false instead of
rejected status.

* fix: account for rejected promises in SES suppression removal

Updated the filter logic for Promise.allSettled to include 'rejected'
status as well as 'fulfilled' with a 'false' value. This ensures that
any errors occurring before the try block in deleteFromSesSuppressionList
are correctly caught and logged.
2026-02-17 07:49:03 +11:00
Vincent Vu ed4a429a1d fix(doc): Correct API reference in Go package documentation (#354)
* Correct API reference in Go package documentation

Updated description to reference the useSend API instead of Unsend API.

* Update documentation to reflect useSend branding

Added a issue to the package maintainer.

If maintainer isn't actively maintaining the package. Will fork it.

* fix(docs): remove community section and update Go SDK documentation

- Remove community section until content is ready.
- Update Go SDK docs to useSend implementation.
2026-02-17 07:43:13 +11:00
Dave Stockley 752fe5a183 feat: add get-campaigns docs (#351) 2026-02-16 16:27:44 +11:00
KM Koushik 487902421b feat: add web testing foundation with infra-backed suites (#349)
* feat: add web test framework with infra-backed suites

* fix: honor DATABASE_URL env in integration prepare script

* fix: apply web test review feedback

* fix: streamline web test infra lifecycle and workflow scope
2026-02-16 09:13:29 +11:00
KM Koushik 09bdb8aaad feat(python-sdk): add webhook verification and event handling (#344)
* feat(python-sdk): add webhook verification and event handling

Add webhook support to the Python SDK matching the JS SDK implementation:
- Add Webhooks class with verify() and construct_event() methods
- Implement HMAC-SHA256 signature verification with timing-safe comparison
- Add timestamp validation with configurable tolerance (default 5 minutes)
- Add comprehensive webhook event types (18 events: email, contact, domain, test)
- Add WebhookVerificationError with typed error codes
- Export webhook constants (headers) and types

* fix(python-sdk): harden webhook parsing and typing

Normalize invalid UTF-8 webhook payloads to INVALID_BODY errors so verify() safely returns false, and narrow base email webhook event types to avoid discriminated-union overlap. Add regression tests for both paths.

* chore(python-sdk): bump package version to 0.2.9

* feat(python-sdk): add local webhook test example project

Add a runnable Flask receiver and signed webhook sender under packages/python-sdk/example, and link it from the Python SDK README for local verification.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-08 08:18:14 +11:00
KM Koushik e246d32ef9 fix: prevent duplicate notification emails via atomic Redis SET NX (#346)
The warning and limit-reached notification emails were being sent
multiple times because of a race condition: concurrent workers could
both read the Redis cooldown key as empty (GET), both send emails,
then both set the key (SETEX). Replaced the non-atomic GET + SETEX
pattern with a single atomic SET ... NX EX that claims the cooldown
slot before any emails are sent. Also increased cooldown from 6 hours
to 24 hours so each notification is sent at most once per day.

https://claude.ai/code/session_01VBYXi5e64Vtq1cXWsfTYTw

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 07:24:02 +11:00
KM Koushik 1b3b8f5751 fix: add repository field for npm provenance 2026-01-18 22:08:26 +11:00
KM Koushik 4c4d150dba fix: configure npm OIDC trusted publishing correctly 2026-01-18 22:03:24 +11:00
KM Koushik b3b7bddafb Change publish command from pnpm to npm 2026-01-18 21:56:01 +11:00