Skip to content

Delete duplicate InMemoryPersister reimplementations across language bindings #1529

Closed

Description

@DanGould

Each language binding reimplements InMemoryPersisters for the receiver and sender in tests, we could do a big code deletion there now that it's exposed.

Originally posted by @spacebear21 in #1528 (comment)

Fed this comment into my meta context for #1528 to produce this issue which should be a sufficient prompt for the run that closes it. I sanity checked the below prompt and find the direction, acceptable. Per-language commits were not my idea but sound sane and easier to review without conflating one problem for another.

In terms of sequencing this makes sense to do before payjoin-ffi-1.0, before someone hand-rolls another JsonSenderSessionpersister or if someone ~junior is exceedingly confident confident they can earn the glory of getting it merged it in one-shot review-then-merge cycle (feeling free to ask clarifying questions before requesting review).


PR #1528 promoted payjoin::persist::InMemoryPersister to public, unconditional Rust
API and re-exported it from payjoin-ffi (payjoin-ffi/src/lib.rs:14). However,
payjoin-ffi exposes session persistence to bindings via the
JsonReceiverSessionPersister / JsonSenderSessionPersister traits (defined in
payjoin-ffi/src/receive/mod.rs and payjoin-ffi/src/send/mod.rs with
#[uniffi::export(with_foreign)]). Bindings implement those traits in their own
language, and each one currently reimplements an in-memory event log:

  • Dart — InMemoryReceiverPersister, InMemorySenderPersister in
    payjoin-ffi/dart/test/test_payjoin_integration_test.dart
  • Python — InMemoryReceiverSessionEventLog, InMemorySenderPersister in
    payjoin-ffi/python/test/test_payjoin_integration_test.py
  • C# — InMemoryReceiverPersister, InMemorySenderPersister in
    payjoin-ffi/csharp/IntegrationTests.cs

These are functionally identical: append events to a list, return the list on load,
set a closed flag.

Proposed work (stage)

  1. payjoin-ffi — add uniffi-exposed in-memory persister types that implement
    JsonReceiverSessionPersister, JsonReceiverSessionPersisterAsync,
    JsonSenderSessionPersister, JsonSenderSessionPersisterAsync and wrap the Rust
    payjoin::persist::InMemoryPersister. Suggested names: InMemoryReceiverPersister,
    InMemoryReceiverPersisterAsync, InMemorySenderPersister,
    InMemorySenderPersisterAsync. Gate them behind the existing
    payjoin-ffi/_test-utils feature so they ship to binding test scripts but don't bloat
    the production FFI surface.

  2. Per-language cleanup PRs (one each, mergeable independently after step 1):

    • Dart — delete the two test classes, regenerate uniffi bindings, swap call sites
    • Python — same
    • C# — same

Each binding PR is pure deletion + regen + import-swap once step 1 lands. Mechanical.

Why split

Step 1 needs core/FFI review attention (uniffi annotations, feature gating, async
variant). Steps 2a/b/c need per-language test verification (Dart hooks, Python uv +
bindgen, C# dotnet + bindgen). Splitting also lets the binding owners review their
own surface.

Out of scope

  • Deduping anything else across bindings (this issue is scoped strictly to the
    InMemoryPersister reimplementations spacebear flagged)
  • Production code changes — the in-memory variant is for tests/examples/prototyping only

Activity

  1. spacebear21 commented on May 13, 2026

    @spacebear21
    Collaborator

    Superseded by #1553

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions