Skip to content
This repository was archived by the owner on Jul 21, 2026. It is now read-only.

feat: add support to coupons#39

Merged
almeidazs merged 15 commits into
mainfrom
feat/coupons
Jun 15, 2026
Merged

feat: add support to coupons#39
almeidazs merged 15 commits into
mainfrom
feat/coupons

Conversation

@almeidazs

@almeidazs almeidazs commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Release Notes

  • New Features

    • Added the @paymesh/dodo provider (catalog-driven hosted checkout, customer management, subscriptions, and normalized webhooks).
    • Added full coupons support end-to-end: CRUD, check validation, coupon webhook events, and integration with payments.create (coupon code application options).
  • Documentation

    • Added Dodo provider installation/setup and capability/PIX guidance (Dodo can show Pix in hosted BRL checkouts, without exposing paymesh.pix).
    • Added/expanded coupons documentation and updated Getting Started/installation to include Dodo and coupon inputs.

@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
paymesh Ready Ready Preview, Comment Jun 15, 2026 1:23pm

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds @paymesh/dodo as a first-party provider and introduces a normalized coupons domain across the Paymesh client, database adapters, webhook handling, migrations, tests, and docs.

Changes

@paymesh/dodo provider

Layer / File(s) Summary
Package scaffold and provider types
packages/dodo/package.json, packages/dodo/tsconfig.json, packages/dodo/tsdown.config.mjs, packages/dodo/src/types.ts, packages/dodo/src/shared/*
Adds the Dodo package manifest and build config, public Dodo types, shared constants, mappers, utilities, webhook helpers, and dashboard sync helpers.
Provider entrypoint and tests
packages/dodo/src/index.ts, packages/dodo/test/*.test.ts
Implements hosted checkout, customer, catalog, dashboard, and webhook provider behavior, with tests covering request mapping, validation, sync flows, and webhook normalization.
Docs and registration
packages/cli/src/shared/providers.ts, apps/web/..., packages/paymesh/README.md, .changeset/cyan-poems-boil.md
Registers Dodo in CLI/docs/web navigation, adds the provider docs page and supporting documentation updates, and adds the release note entry.

Normalized coupons feature

Layer / File(s) Summary
Coupon types and client contracts
packages/paymesh/src/types/providers.ts, packages/paymesh/src/types/database.ts, packages/paymesh/src/types/client.ts, packages/paymesh/src/database/schema.ts
Adds coupon domain types, provider and repository contracts, client interfaces, webhook event types, and the built-in coupons table key.
Coupons client wiring
packages/paymesh/src/client/coupons.ts, packages/paymesh/src/client/managers.ts
Implements the coupons client and attaches it to PaymeshClient.
Coupon storage and webhook persistence
packages/drizzle/src/repositories.ts, packages/postgres/src/repositories.ts, packages/prisma/src/repositories.ts, packages/memory/src/repositories.ts, packages/memory/src/state.ts, packages/memory/src/types.ts, packages/paymesh/src/database/webhooks.ts, packages/paymesh/src/plugins/runtime.ts, packages/paymesh/src/database/schema.ts
Adds coupon repositories and memory-state support, updates cursor decoding, persists coupon lifecycle webhook events, and reserves coupon hook names.
CLI migrations for coupons table
packages/cli/src/lib/migrations.ts, packages/cli/test/cli.test.ts
Adds the built-in coupons table migration SQL, indexes, and constraints, and updates the migration test expectation.
Coupon tests and docs
packages/paymesh/test/client.test.ts, packages/paymesh/test/database.test.ts, apps/web/content/docs/concepts/coupons.mdx, apps/web/content/docs/concepts/api.mdx, apps/web/content/docs/guides/create-a-provider.mdx, apps/web/src/lib/docs-navigation.ts
Adds client/database coverage for coupon flows and documents the coupons API surface, checkout inputs, and navigation entry.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant PaymeshClient
  participant couponsClient as createCouponsClient
  participant providerCoupons as provider.coupons
  participant CouponsRepo as PaymeshCouponsRepository

  App->>PaymeshClient: coupons.create(data)
  PaymeshClient->>couponsClient: create(data)
  couponsClient->>providerCoupons: create(provider fields)
  providerCoupons-->>couponsClient: Coupon
  couponsClient->>CouponsRepo: upsert(schema, coupon)
  CouponsRepo-->>couponsClient: stored coupon
  couponsClient-->>PaymeshClient: Coupon
  PaymeshClient-->>App: normalized coupon

  App->>PaymeshClient: webhooks.handle(event)
  PaymeshClient->>providerCoupons: webhook normalization
  providerCoupons->>CouponsRepo: findByProviderId()
  providerCoupons->>CouponsRepo: upsert()/markDeleted()
  providerCoupons-->>PaymeshClient: normalized coupon event
  PaymeshClient-->>App: hook + event
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

  • feat(coupons): add support #25 — This PR adds the coupon domain end-to-end across providers, client, repositories, migrations, webhook handling, and docs, matching the issue’s coupon-support scope.

Possibly related PRs

  • usepaymesh/paymesh#27 — The Dodo docs wiring changes extend the same web documentation infrastructure.
  • usepaymesh/paymesh#36 — The new coupon repository support extends the memory adapter introduced there.
  • usepaymesh/paymesh#24 — The coupon webhook hook-name additions extend the built-in hook system changed there.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/coupons

@almeidazs almeidazs changed the title feat feat: add support to coupons Jun 15, 2026
@almeidazs almeidazs self-assigned this Jun 15, 2026
@almeidazs
almeidazs marked this pull request as draft June 15, 2026 01:48
@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation enhancement New feature or request labels Jun 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cli/test/cli.test.ts (1)

912-917: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the comment to include coupons in the table list.

The expectation was correctly updated to 12, but the comment on lines 914-915 still lists only 11 tables and doesn't mention coupons.

📝 Suggested fix
 		// Each built-in sandbox table should have a DO $$ block for constraint replacement
 		const doBlocks = (sandboxMigration?.sql.match(/DO \$\$/g) ?? []).length;
-		// 11 built-in sandbox tables: customers, pix, checkouts, invoices,
+		// 12 built-in sandbox tables: customers, coupons, pix, checkouts, invoices,
 		// paymentMethods, entitlements, usage, webhookEvents, subscriptions, products, prices
 		expect(doBlocks).toBe(12);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/test/cli.test.ts` around lines 912 - 917, Update the comment
block that documents the built-in sandbox tables to reflect the current count
and include the coupons table. Change the count from "11 built-in sandbox
tables" to "12 built-in sandbox tables" and add coupons to the comma-separated
list of table names (customers, pix, checkouts, invoices, paymentMethods,
entitlements, usage, webhookEvents, subscriptions, products, prices) to match
the expect statement that verifies doBlocks equals 12.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/content/docs/concepts/coupons.mdx`:
- Line 420: The file apps/web/content/docs/concepts/coupons.mdx contains
hardcoded absolute file system paths in documentation links at lines 420 and 434
instead of using the relative documentation link format used throughout the
codebase. At line 420, replace the absolute path
/home/almeida/Documents/Projects/paymesh/paymesh/apps/web/content/docs/providers/stripe.mdx
with the relative documentation path /docs/providers/stripe (removing the
leading full system path and the .mdx extension). Similarly, at line 434,
replace any absolute path reference to the Polar provider with
/docs/providers/polar using the same format. This will ensure the documentation
links follow the consistent `/docs/[path]` pattern used throughout the codebase
and allow proper navigation.

In `@apps/web/public/llms.txt`:
- Line 12: The file `apps/web/public/llms.txt` now includes `@paymesh/dodo` in
the "Official live providers" list, but the "Recommended documentation
entrypoints → Providers" section is missing the corresponding
`/docs/providers/dodo` entry. Add `/docs/providers/dodo` to the Providers
documentation list in the same file to keep these two sections aligned and
consistent.

In `@apps/web/src/lib/docs.tsx`:
- Around line 3871-3884: The documentation states that delete is intentionally
unsupported for Dodo customers, but the DocCodeBlock component currently renders
customerSnippet which includes an unsupported delete operation. Replace the
customerSnippet variable reference with a Dodo-specific code snippet that only
demonstrates the supported upsert and get operations for customers, ensuring the
code example matches the documented behavior.

In `@packages/dodo/src/index.ts`:
- Around line 301-313: Add validation for the event.data shape immediately after
validating event and event.type in the webhook payload check. Before calling
resolveDodoWebhookData, check that event.data exists and is an object (using
isRecord or similar validation), and throw a TypeError with a clear message if
validation fails. This ensures malformed webhook data is rejected early with a
deterministic error instead of failing downstream during resolver mapping.

In `@packages/dodo/src/shared/constants.ts`:
- Around line 44-46: The mapping in the constants file incorrectly remaps
refund.failed to payment.failed, which causes refund operation failures to be
treated as payment lifecycle failures and can incorrectly downgrade a successful
payment state. Remove or replace the line that maps 'refund.failed' to
'payment.failed' with an appropriate mapping that correctly represents a refund
failure without affecting payment state transitions.

In `@packages/dodo/src/shared/sync.ts`:
- Around line 57-67: The Promise.all call at line 57 executes the invoice and
Pix upserts concurrently, which can lead to partial persistence if one succeeds
and the other fails. Instead, await the database.repositories.invoices.upsert
operation first, then conditionally execute the Pix upsert only after the
invoice is successfully persisted. This ensures deterministic persistence where
Pix data cannot be stored independently of its parent payment record,
maintaining consistency within a single sync unit.

In `@packages/dodo/src/shared/utils.ts`:
- Around line 165-195: The validation in ensureDodoProductIds function only
checks array length but does not validate that each product ID is a valid
non-empty string, allowing invalid entries to pass through. Additionally, the
validation in buildDodoProductCart function only checks typeof for amount being
a number, but does not validate that it is a valid positive number (allowing
NaN, Infinity, or values <= 0). Strengthen ensureDodoProductIds to iterate
through productIds and verify each is a non-empty string, and enhance the amount
validation in buildDodoProductCart to check that the numeric value is finite and
greater than zero before allowing it to be used in the cart.

In `@packages/dodo/src/shared/webhooks.ts`:
- Around line 53-58: The resolveDodoWebhookType function defaults unmapped
webhook types to payment.created using the ?? operator, which causes unsupported
events to be misrouted to payment handlers with incorrect semantics. Remove the
fallback to payment.created from the expression DODO_EVENTS[type] ??
'payment.created' and instead throw an error or handle unknown types explicitly
to prevent silent misclassification of webhooks that do not have proper event
mappings defined.

In `@packages/dodo/test/dodo.test.ts`:
- Around line 192-227: The three expect statements using
.rejects.toMatchObject() are not awaited or returned, which means the test can
complete before the rejection checks run, causing false-positive passing tests.
Add await before each of the three expect() calls that check for rejections from
provider.payments.create() to ensure the Promise rejections are properly
validated before the test completes.

In `@packages/drizzle/src/repositories.ts`:
- Around line 438-441: The coupons.list implementation is currently using
decodeCustomerCursor which produces customer-specific error messages when
validating coupon cursors. Replace the decodeCustomerCursor call in
packages/drizzle/src/repositories.ts at lines 438-441,
packages/postgres/src/repositories.ts at lines 438-441, and
packages/prisma/src/repositories.ts at lines 438-441 with a coupon-specific
decoder that generates appropriate coupon error messaging. Additionally, apply
the same coupon-specific decoder change to packages/memory/src/repositories.ts
at lines 313-316. Either create a separate decodeCouponCursor function or
parameterize the shared decoder with an entity context parameter that allows it
to return entity-appropriate error labels.

In `@packages/paymesh/src/client/coupons.ts`:
- Around line 206-208: The local markDeleted call on couponsRepository is not
gated on the success of the provider-side deletion operation. Currently, it
executes whenever couponsRepository exists, regardless of whether the provider
deletion succeeded. Add an additional condition to check that result.deleted is
true before calling couponsRepository.markDeleted(schema, result), so that local
tombstoning only occurs after confirming the provider-side deletion was
successful.

In `@packages/paymesh/src/types/client.ts`:
- Around line 302-306: The PaymeshCouponUpdateData type definition requires all
schema-required coupon extra fields from DatabaseTableInputExtraFields to be
provided on every update, breaking partial update semantics. Modify the type
definition to make the DatabaseTableInputExtraFields extra fields optional by
wrapping them with Partial<> utility type, allowing callers to perform partial
updates without needing to provide all custom required columns.

In `@packages/paymesh/src/types/database.ts`:
- Around line 431-446: The PaymeshCouponListOptions interface is missing the
status field that exists in the provider's CouponListOptions type. Add a status
field to PaymeshCouponListOptions to enable status filtering for coupon list
queries, matching the provider contract. This will allow client.coupons.list()
to accept and forward the status filter parameter correctly.

---

Outside diff comments:
In `@packages/cli/test/cli.test.ts`:
- Around line 912-917: Update the comment block that documents the built-in
sandbox tables to reflect the current count and include the coupons table.
Change the count from "11 built-in sandbox tables" to "12 built-in sandbox
tables" and add coupons to the comma-separated list of table names (customers,
pix, checkouts, invoices, paymentMethods, entitlements, usage, webhookEvents,
subscriptions, products, prices) to match the expect statement that verifies
doBlocks equals 12.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a633df1-c58e-45e7-927b-6f454dd473d4

📥 Commits

Reviewing files that changed from the base of the PR and between a148077 and a1708ee.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (52)
  • .changeset/cyan-poems-boil.md
  • README.md
  • apps/web/.source/browser.ts
  • apps/web/.source/server.ts
  • apps/web/content/docs/basic-usage.mdx
  • apps/web/content/docs/concepts/api.mdx
  • apps/web/content/docs/concepts/coupons.mdx
  • apps/web/content/docs/concepts/payment-providers.mdx
  • apps/web/content/docs/concepts/pix.mdx
  • apps/web/content/docs/guides/create-a-provider.mdx
  • apps/web/content/docs/installation.mdx
  • apps/web/content/docs/introduction.mdx
  • apps/web/content/docs/providers/dodo.mdx
  • apps/web/public/llms.txt
  • apps/web/src/app/page.tsx
  • apps/web/src/components/docs/mdx-components.tsx
  • apps/web/src/lib/docs-navigation.ts
  • apps/web/src/lib/docs.tsx
  • package.json
  • packages/cli/src/lib/migrations.ts
  • packages/cli/src/shared/providers.ts
  • packages/cli/test/cli.test.ts
  • packages/dodo/README.md
  • packages/dodo/package.json
  • packages/dodo/src/index.ts
  • packages/dodo/src/shared/constants.ts
  • packages/dodo/src/shared/mapper.ts
  • packages/dodo/src/shared/sync.ts
  • packages/dodo/src/shared/utils.ts
  • packages/dodo/src/shared/webhooks.ts
  • packages/dodo/src/types.ts
  • packages/dodo/test/catalog.test.ts
  • packages/dodo/test/customers.test.ts
  • packages/dodo/test/dashboard.test.ts
  • packages/dodo/test/dodo.test.ts
  • packages/dodo/test/webhooks.test.ts
  • packages/dodo/tsconfig.json
  • packages/dodo/tsdown.config.mjs
  • packages/drizzle/src/repositories.ts
  • packages/memory/src/repositories.ts
  • packages/memory/src/state.ts
  • packages/memory/src/types.ts
  • packages/paymesh/README.md
  • packages/paymesh/src/client/coupons.ts
  • packages/paymesh/src/client/managers.ts
  • packages/paymesh/src/database/schema.ts
  • packages/paymesh/src/types/client.ts
  • packages/paymesh/src/types/database.ts
  • packages/paymesh/src/types/providers.ts
  • packages/paymesh/test/client.test.ts
  • packages/postgres/src/repositories.ts
  • packages/prisma/src/repositories.ts

Comment thread apps/web/content/docs/concepts/coupons.mdx Outdated
Comment thread apps/web/public/llms.txt
Comment thread apps/web/src/lib/docs.tsx
Comment thread packages/dodo/src/index.ts
Comment thread packages/dodo/src/shared/constants.ts
Comment thread packages/dodo/test/dodo.test.ts Outdated
Comment thread packages/drizzle/src/repositories.ts
Comment thread packages/paymesh/src/client/coupons.ts Outdated
Comment thread packages/paymesh/src/types/client.ts
Comment thread packages/paymesh/src/types/database.ts
@almeidazs
almeidazs marked this pull request as ready for review June 15, 2026 13:23
@almeidazs
almeidazs merged commit 93bd12c into main Jun 15, 2026
12 of 13 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant