@makecrypto/medusa-plugin-digital-downloads makes digital goods feel like a
native Medusa product capability. A merchant continues to use Medusa products,
variants, pricing, sales channels, orders, customers, payments, notifications,
and the Admin dashboard. The plugin adds the digital-specific concepts that
Medusa does not provide: protected assets, releases, purchase entitlements,
download grants, license keys, activations, and a customer library.
The plugin is payment-provider agnostic and works with MakePay's Medusa payment
provider without coupling fulfillment to MakePay-specific data. Version 1 is
developed and host-tested against Medusa v2.18 and declares the supported
runtime range >=2.18 <3.
Version 1.0 is complete only when all of the following are true:
- The package installs as a standard Medusa plugin and migrations run on a clean PostgreSQL database.
- A merchant can attach a digital configuration to a product variant from the Medusa Admin, upload private files, publish a release, configure delivery and license rules, and inspect fulfillment on an order.
- A customer or guest can complete a normal Medusa checkout and receive an idempotent entitlement for every purchased digital line and quantity.
- Access checks always bind an asset or license to the authenticated customer or a valid guest capability, a non-revoked entitlement, and the purchased release snapshot.
- Local protected storage and private S3-compatible storage both work. A private object is never exposed as a permanent public URL.
- Downloads support expiry, limits, revocation, optional first-IP binding, checksums, safe filenames, and single byte ranges for seekable media.
- Generated and imported software licenses support secure recovery, expiry, activation limits, activation/deactivation/heartbeat, and audit history.
- Mixed physical/digital carts, guest and registered buyers, free orders, quantity greater than one, retries, duplicate events, cancellation, refund, deleted catalog records, and expired access are covered by tests.
- Admin routes/widgets, a typed storefront client, accessible React UI primitives, account-library and native order-history Next.js examples, notification-provider/template examples, and an OpenAPI 3.1 document ship in the package.
- Lint, strict type checking, unit tests, PostgreSQL module/API integration tests, plugin build, package-content validation, clean-install validation, and real-browser scenarios pass in repeated runs.
- One digital configuration per Medusa product variant, while preserving the standard Product and Variant records as the merchant-facing source of truth.
- Mixed physical and digital orders without replacing Medusa's cart completion endpoint or forcing a MakePay-only checkout.
- Multiple protected and preview assets per product release.
- Product types: generic file/archive, PDF or ebook, audio, video, photo or art, and software license.
- Delivery modes: download, protected stream, license only, or content plus a
license (
mixed). - Draft, published, superseded, and retired releases; every delivery mode uses a published immutable fulfillment snapshot so later catalog edits cannot redirect an old purchase. License-only releases may have zero assets when an enabled generated or pooled license policy supplies the deliverable.
- Protected local filesystem storage and private S3/S3-compatible storage, including AWS S3, MinIO, Cloudflare R2, DigitalOcean Spaces, and Supabase's S3 endpoint when configured with compatible credentials.
- Admin upload, server-side filename normalization, declared and detected MIME metadata, byte size, SHA-256 checksum, sort order, label, version, and preview classification.
- Idempotent entitlement issuance for registered customers and guest email purchases. An order event may be delivered more than once without producing duplicate ownership or license keys.
- Entitlement lifecycle: pending, active, suspended, expired, refunded, revoked.
- Per-product or store-default download count, content-grant lifetime, distinct guest purchase-capability lifetime, entitlement lifetime, streaming policy, first-IP lock, and refund/cancellation behavior.
- Opaque, short-lived, asset-bound download grants. Stored data contains only a hash of a live bearer token.
- Generated license patterns and imported license pools, encrypted recoverable values, normalized lookup hashes, per-purchase assignments, expiration, activation limits, and lifecycle controls.
- Customer-authenticated library and guest-capability access with safe
projections and
Cache-Control: private, no-storeon secret-bearing replies. - Product detail and order detail Admin widgets plus complete Digital Downloads list, detail, create/edit, entitlement, license-pool, and settings pages.
- A restrained, accessible “Brought to you by MakePay.io — crypto payment
gateway.” attribution in the plugin Admin and supplied storefront UI, using a
fixed safe
https://makepay.iodestination and never altering checkout.
- Preview metadata and public preview retrieval without exposing master assets.
- Audio/video single-range streaming and standards-compliant
206,Content-Range,Accept-Ranges, and unsatisfiable-range behavior. - Protected content is
GET-only in version 1. A futureHEADroute must have explicit grant authorization and non-consuming semantics; it must not rely on an implicit Express fallback that could reserve or count a download. - Typed storefront client with pluggable
fetch, publishable-key support, customer bearer/session support, guest capability support, and normalized errors. - Accessible Digital Library, Product Preview, Download Action, License Reveal, and License Activation React primitives with loading, empty, error, revoked, expired, and limit-reached states.
- Next.js Medusa starter integration showing product previews, an account library, and order-scoped delivery in native customer order history without replacing core checkout code.
- Optional Notification Module delivery driven by plugin events and merchant template identifiers, with a copy-ready provider/template example. The host owns rendering, branding, credentials, and transport; email failure never rolls back ownership and is visible for retry.
- Admin filters, search, stable pagination, status totals, bulk revoke/reactivate, resend/reissue, license-pool capacity, and storage-health indicators.
- Scheduled entitlement expiry and orphaned Medusa product-link reconciliation. Expired upload/grant rows, audit retention, and unreferenced object deletion require an operator-approved, database-aware retention job; version 0.4 does not delete physical objects automatically.
- OpenAPI 3.1 contracts and copy-ready environment/configuration examples.
- Download and license audit exports without bearer tokens, decrypted keys, full IP addresses, storage credentials, or private object keys.
- Optimistic or lock-backed allocation so concurrent license issuance and activation cannot exceed inventory or activation limits.
- Admin manual entitlement issuance for support cases with an explicit actor, reason, and audit event.
- Entitlement update policy allowing access to the purchased release only or to newer published releases within an optional update window.
- Idempotency keys for mutation APIs in addition to workflow-level natural keys.
- Storage verification that confirms an uploaded asset exists and matches the persisted size/checksum before publication.
- DRM. Protected streaming reduces casual sharing but cannot prevent recording.
- Arbitrary remote origin URLs. They require a complete SSRF, redirect, DNS rebinding, proxy, authentication-header, and availability threat model. Local and S3-compatible storage cover the requested v1 storage scope safely.
- A second catalog, cart, checkout, price engine, customer account system, or payment page. Medusa remains responsible for all core commerce behavior.
- Editing Medusa's built-in Admin layout. The plugin uses supported routes, widgets, Medusa UI, and Admin SDK injection zones.
- Permanent plaintext storage of license keys, guest access secrets, download bearer tokens, storage secrets, or full client IP addresses.
- Audit the existing MakePay provider's packaging and Medusa compatibility.
- Inventory BTCPay Digital Products features, security invariants, migrations, operations, UX, tests, and known architectural limitations.
- Use the official Medusa digital-products recipe as a starting reference, not as a production implementation: remove its custom cart-completion override, make delivery idempotent, snapshot purchased terms, and add revocation.
- Pin implementation decisions to current official Medusa plugin, module, File Module, Admin extension, workflow, and test documentation.
- Finalize model names, natural idempotency keys, indexes, and link directions.
- Define workflow inputs/outputs/compensation and event payload schemas.
- Define safe Admin and Store projections independently of persistence models.
- Define plugin options, database-managed settings, secret precedence, and storage-driver interfaces.
- Threat-model every route that returns or accepts a capability or license.
- Scaffold with
create-medusa-app@2.18.0 --plugin. - Add package exports, npm metadata, lint/type/test/build/package gates, Node 20/22 CI, PostgreSQL CI, release-tag validation, changelog, security policy, architecture, configuration, API, storefront, and testing documentation.
- Implement models and relations inside the Digital Downloads module.
- Generate and inspect MikroORM migrations and snapshots.
- Exercise up/down/clean migration behavior on PostgreSQL.
- Add indexes for variant lookup, order-line idempotency, entitlement library, token hashes, license hashes, release publication, and audit pagination.
- Implement a common protected-storage interface with local and S3 drivers.
- Validate configuration at startup; keep local roots out of web-static paths.
- Use CSPRNG bearer secrets, SHA-256 lookup hashes, timing-safe comparisons, and AES-256-GCM envelopes for data that must be recovered.
- Verify file boundaries, canonical paths, S3 prefixes, checksums, content type, byte ranges, response headers, and deletion safety.
- Product/release/asset creation, publication, retirement, and deletion.
- Entitlement issuance keyed by order and line item; license assignment keyed by entitlement and unit index.
- Cancellation/refund/revoke/reactivate and manual support flows.
- Download grant creation/consumption and license activation transactions.
- Event emission, notifications, retry state, and scheduled cleanup.
- Admin CRUD, uploads, publication, entitlements, licenses, audit, settings, storage health, manual support actions, and pagination.
- Store previews, authenticated library, guest library, entitlement detail, download/stream grant and content delivery, license reveal, validate, activate, deactivate, and heartbeat.
- Zod validation, actor checks, rate limiting, no-store headers, error mapping, safe projections, idempotency, range parsing, and OpenAPI coverage.
- Medusa UI routes, product/order widgets, form validation, tables, filters, upload progress, license capacity, destructive-action confirmations, and i18n.
- Typed client, React primitives, and Next.js integration.
- Keyboard, focus, label, status, loading, empty, error, responsive, and dark-mode checks.
- Pure unit tests for parsing, validation, tokens, encryption, patterns, projections, limits, ranges, filenames, paths, and edge cases.
- Service/module integration tests with a real PostgreSQL database.
- HTTP integration tests covering authentication, authorization, persistence, range delivery, no-store behavior, and idempotency.
- Packed-plugin install into a clean Medusa application, migrations, seed data, local storage, and a MinIO S3-compatible test.
- Real-browser merchant and customer flows against Admin and storefront.
- Adversarial cases: cross-customer IDs, forged guest tokens, altered asset IDs, traversal names, malformed ranges, reused grants, revoked access, expired access, duplicate events, concurrent activations, and missing storage objects.
- Clean checkout plus MakePay provider simulation, free order, guest order, registered order, mixed cart, quantity, cancellation, partial/full refund, catalog deletion, and re-published releases.
- Re-run lint/type/build/test/package, dependency audit, security scan, clean install, and regression suites after all fixes.
- Synchronize package, changelog, docs, git tag, and GitHub release versions.
- Require green Node and PostgreSQL checks and a conflict-free release PR.
- Inspect the packed tarball; install it into a clean fixture from the tarball.
- Merge the verified PR to
main, tagv1.0.0, create the GitHub release, and publish to npm when the repository'sNPM_TOKENpermission is available.
The automated and manual test ledger must include at least:
- One variant with two protected files and one public preview.
- PDF preview plus protected ebook download.
- Seekable audio and video with valid, suffix, open-ended, malformed, and unsatisfiable byte ranges.
- Photo preview metadata with a protected original.
- Generated-license product with two purchased units and two distinct keys.
- Imported-license pool exhaustion and safe rollback.
- Concurrent attempts to claim the final pool key.
- Activation limit reached, deactivate then reactivate, expired, suspended, and revoked license responses.
- Customer A attempting every Customer B entitlement, asset, grant, and license identifier.
- Guest token creation, use, rotation/reissue, expiry, revocation, and leakage checks in logs, URLs, caches, and API projections.
- Download limit zero/unlimited, one, and many; a range continuation must not consume a second entitlement download unexpectedly.
- Duplicate
order.placed, retry after a mid-workflow failure, and two workers processing the same order. - Full and partial cancellation/refund policies.
- Product edits and deletion after purchase; the original purchase remains understandable and never points at a different file.
- Local and S3 upload, retrieve, range, missing object, checksum mismatch, invalid credentials, and cleanup failure.
- Admin loading/empty/error/pagination/filter/bulk flows and storefront loading/empty/error/expired/revoked/limit-reached flows at desktop and mobile.