Skip to content

bindings/node: add Client.joinGroupByExternalInvite NAPI binding#3676

Open
tylerhawkes wants to merge 10 commits into
tyler/qr-invite-l11-join-by-invitefrom
tyler/qr-invite-b2-napi-join
Open

bindings/node: add Client.joinGroupByExternalInvite NAPI binding#3676
tylerhawkes wants to merge 10 commits into
tyler/qr-invite-l11-join-by-invitefrom
tyler/qr-invite-b2-napi-join

Conversation

@tylerhawkes

@tylerhawkes tylerhawkes commented May 21, 2026

Copy link
Copy Markdown
Contributor

Summary

NAPI binding for Client::join_group_by_external_invite (PR-L11).

  • New file bindings/node/src/client/external_invite.rs.
  • Buffer in (invite payload bytes + encrypted blob bytes), returns the new conversation handle plus the refreshed encrypted blob bytes the application should upload to its service slot.

Stack

Test plan

  • cargo check -p bindings_node passes.
  • End-to-end smoke test wired up via PR-T1's NAPI smoke (follow-on).

Note

Add Client.joinGroupByExternalInvite NAPI binding to Node bindings

Adds an async join_group_by_external_invite method to the Node.js Client binding in external_invite.rs. The method accepts invite_payload and encrypted_group_info as Uint8Array, delegates to the inner client, and returns a new JoinGroupByExternalInviteOutput object exposing the joined Conversation and a refreshed_encrypted_group_info Uint8Array.

Macroscope summarized b5b3b51.

@tylerhawkes tylerhawkes requested a review from a team as a code owner May 21, 2026 08:22
@claude

claude Bot commented May 21, 2026

Copy link
Copy Markdown

Claude finished @tylerhawkes's task —— View job


PR Review

Todo List

  • Read changed files
  • Review code for quality, bugs, performance, security, and test coverage
  • Post review feedback

Code Review — 2026-05-27 18:34 UTC

The binding implementation is clean and follows established patterns in the codebase. I have one minor observation:

Observation

Getter method clones unnecessarily (bindings/node/src/client/external_invite.rs:25-27)

The conversation() getter clones the Conversation struct. While this works correctly, it's worth noting that:

  • Conversation wraps a RustMlsGroup (which is MlsGroup<MlsContext>), and contains Arc-wrapped internals
  • The clone is relatively cheap due to Arc reference counting, but creates a new wrapper struct
  • This pattern is consistent with other NAPI bindings in this codebase (e.g., other methods return cloned Conversation objects)

No change needed — this follows the existing NAPI patterns and performs acceptably.

Summary

✅ Code quality: Clean, idiomatic NAPI binding
✅ Error handling: Properly uses ErrorWrapper::from
✅ Type conversions: Correct use of Uint8ArrayVec<u8> via .as_ref() and .into()
✅ Documentation: Well-documented with clear explanation of the refresh workflow
✅ Security: No concerns; delegates to underlying Rust implementation
✅ Performance: Appropriate for binding layer
⚠️ Test coverage: As noted in PR description, end-to-end testing is follow-on work (tracked separately)

The implementation correctly wraps the Rust functionality and maintains the expected contract for external invite joining.


@macroscopeapp

macroscopeapp Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved

This PR adds a Node.js NAPI binding that wraps an existing Rust method without introducing new business logic. The changes are a standard binding layer with type marshaling, and the author owns all modified files.

No code changes detected at b5b3b51. Prior analysis still applies.

You can customize Macroscope's approvability policy. Learn more.

@codecov

codecov Bot commented May 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (tyler/qr-invite-l11-join-by-invite@a6ec61d). Learn more about missing BASE report.

Additional details and impacted files
@@                          Coverage Diff                          @@
##             tyler/qr-invite-l11-join-by-invite    #3676   +/-   ##
=====================================================================
  Coverage                                      ?   83.63%           
=====================================================================
  Files                                         ?      403           
  Lines                                         ?    59878           
  Branches                                      ?        0           
=====================================================================
  Hits                                          ?    50079           
  Misses                                        ?     9799           
  Partials                                      ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tylerhawkes tylerhawkes force-pushed the tyler/qr-invite-l11-join-by-invite branch 2 times, most recently from df41a55 to dab038e Compare May 26, 2026 22:59
@tylerhawkes tylerhawkes force-pushed the tyler/qr-invite-l11-join-by-invite branch from dab038e to f0d63d4 Compare May 27, 2026 18:17
@tylerhawkes tylerhawkes force-pushed the tyler/qr-invite-b2-napi-join branch from e9e80a9 to 66f7743 Compare May 27, 2026 18:17
… generic AppDataUpdate intent

Defense-in-depth master switch + per-component declarative external
committer authorization for the QR-invite flow (MLS External Commits,
RFC 9420 §12.4.3.2).

- ComponentId::EXTERNAL_COMMIT_POLICY = 0x800C in xmtp_mls_common.
- Type-dispatch entry: ComponentType::Bytes for the new id.
- crates/xmtp_mls/src/groups/external_commit_policy.rs (new file):
  - load_external_commit_policy(group) -> Option<ExternalCommitPolicyV1>
  - is_external_commit_allowed(group) -> bool
  - external_committer_permissions_for(group, id) -> Option<ComponentPermissions>
- MlsGroup::set_external_commit_policy(policy) — granular setter
  writes the full ExternalCommitPolicyV1 via the generic
  AppDataUpdate intent (AppDataUpdateOp::Replace, since the
  component is full-replace Bytes-typed).
- MlsGroup::set_allow_external_commit(bool) — sugar wrapper.

Depends on L-0 (generic IntentKind::AppDataUpdate) for the intent
machinery. No new IntentKind variant added — the generic path covers
this and every future full-replace component setter.

No bootstrap synth: absent EXTERNAL_COMMIT_POLICY = disabled default.
First setter call creates the entry via AppDataUpdateOperation::Update
upsert semantics. Zero risk of cross-client serialization drift.
@tylerhawkes tylerhawkes force-pushed the tyler/qr-invite-b2-napi-join branch from 66f7743 to b5b3b51 Compare May 27, 2026 18:33
@tylerhawkes tylerhawkes force-pushed the tyler/qr-invite-l11-join-by-invite branch from f0d63d4 to a6ec61d Compare May 27, 2026 18:33
@tylerhawkes tylerhawkes force-pushed the tyler/qr-invite-l11-join-by-invite branch 2 times, most recently from b5b9a53 to 3056397 Compare June 10, 2026 06:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant