Skip to content

Use Claude Code to sync docs with Browser and Node SDKs#657

Open
jhaaaa wants to merge 5 commits intomainfrom
browser-node-sdks-sync
Open

Use Claude Code to sync docs with Browser and Node SDKs#657
jhaaaa wants to merge 5 commits intomainfrom
browser-node-sdks-sync

Conversation

@jhaaaa
Copy link
Contributor

@jhaaaa jhaaaa commented Feb 5, 2026

No description provided.

@jhaaaa jhaaaa requested a review from a team as a code owner February 5, 2026 02:36
@vercel
Copy link

vercel bot commented Feb 5, 2026

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

Project Deployment Actions Updated (UTC)
docs-xmtp-org Ready Ready Preview, Comment Mar 8, 2026 5:29pm

Request Review

@macroscopeapp
Copy link

macroscopeapp bot commented Feb 5, 2026

Sync Browser and Node SDK docs for chat apps with new sections and examples

  • Adds a new browser-storage.mdx page covering the Opfs class for managing browser storage, including backup/restore, export/import, and capacity checks.
  • Expands create-conversations.mdx with identifier-based group/DM creation, async admin checks, pending removal flow, and peerInboxId/creatorInboxId access.
  • Adds manage-inboxes.mdx sections for key package status checks, address/installation authorization (Node only), inbox ID generation/lookup, and recovery identity changes.
  • Expands group-permissions.mdx with custom permission policy creation, retrieval, and per-field updates using group.updatePermission.
  • Adds debug-your-app.mdx sections for duplicate DM inspection, pausedForVersion checks, and API/identity statistics via client.debugInformation.

Macroscope summarized 5306dc9.


:::

## Check if client is registered
Copy link
Contributor Author

Choose a reason for hiding this comment

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

not in mobile SDKs

)
```

```tsx [React Native]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

jha fix order of samples here

After a user calls `leaveGroup()`, you can check if their removal is still being processed using the `membershipState()` method. This is useful for showing appropriate UI while the group removal is being finalized.
After a user requests to leave a group, you can check if their removal is still being processed. This is useful for showing appropriate UI while the group removal is being finalized.

:::code-group
Copy link
Contributor Author

Choose a reason for hiding this comment

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

looks like Browser and Node do this differently than mobile

// Check if current user created the DM
const isDmCreator = dm.isCreator;
```

Copy link
Contributor Author

Choose a reason for hiding this comment

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

isCreator is not in RN

}
```

## Generate and look up inbox IDs
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Browser/Node only, mobile
SDKs use it internally but don't expose it


:::

## Change the recovery identity
Copy link
Contributor Author

Choose a reason for hiding this comment

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

not available in mobile SDKs

@macroscopeapp
Copy link

macroscopeapp bot commented Mar 7, 2026

  • Restructured group permissions API in Browser and Node examples [f8375ef]
  • Changed registration and removal status checks from asynchronous method calls to synchronous property access [f8375ef]
  • Renamed parameters in createGroupWithIdentifiers method calls from generic to specific naming [f8375ef]
  • Removed Browser and Node code examples for specific features [f8375ef]

📊 Macroscope summarized f8375ef. 2 files reviewed, 1 issue evaluated, 0 issues filtered, 1 comment posted. View details

Comment on lines +154 to +161
```js [Browser]
import { IdentifierKind } from "@xmtp/browser-sdk";

// Create identifiers for members
const memberIdentifiers = [
{ kind: IdentifierKind.Ethereum, identifier: "0xMEMBER1_ADDRESS" },
{ kind: IdentifierKind.Ethereum, identifier: "0xMEMBER2_ADDRESS" },
];
Copy link

Choose a reason for hiding this comment

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

🟢 Low core-messaging/create-conversations.mdx:154

The code examples use kind as the property name, but the SDK's Identifier type requires identifierKind. When users copy these examples, the identifiers won't be properly recognized by the SDK and group creation will fail. Change kind to identifierKind in all four identifier objects.

Suggested change
```js [Browser]
import { IdentifierKind } from "@xmtp/browser-sdk";
// Create identifiers for members
const memberIdentifiers = [
{ kind: IdentifierKind.Ethereum, identifier: "0xMEMBER1_ADDRESS" },
{ kind: IdentifierKind.Ethereum, identifier: "0xMEMBER2_ADDRESS" },
];
{ identifierKind: IdentifierKind.Ethereum, identifier: "0xMEMBER1_ADDRESS" },
{ identifierKind: IdentifierKind.Ethereum, identifier: "0xMEMBER2_ADDRESS" },
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file docs/pages/chat-apps/core-messaging/create-conversations.mdx around lines 154-161:

The code examples use `kind` as the property name, but the SDK's `Identifier` type requires `identifierKind`. When users copy these examples, the identifiers won't be properly recognized by the SDK and group creation will fail. Change `kind` to `identifierKind` in all four identifier objects.

@macroscopeapp
Copy link

macroscopeapp bot commented Mar 7, 2026

Approvability

Verdict: Needs human review

I found 7 correctness issues on this PR. While the changes are documentation-only and the author owns the files, these findings make it ineligible for auto-approval.

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


// Example usage: backup current database before clearing
async function backupAndClear(client: Client) {
const dbPath = `./xmtp-${client.inboxId}.db3`;
Copy link

Choose a reason for hiding this comment

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

🟠 High list-stream-sync/browser-storage.mdx:135

Line 135 constructs the database path as ./xmtp-${client.inboxId}.db3, but the Browser SDK actually stores databases at xmtp-${env}-${inboxId}.db3 without the ./ prefix and with the environment included. Users following this example will pass a non-existent path to backupXmtpDatabase, causing exportDb to fail.

Suggested change
const dbPath = `./xmtp-${client.inboxId}.db3`;
const dbPath = `xmtp-${client.env}-${client.inboxId}.db3`;
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file docs/pages/chat-apps/list-stream-sync/browser-storage.mdx around line 135:

Line 135 constructs the database path as `./xmtp-${client.inboxId}.db3`, but the Browser SDK actually stores databases at `xmtp-${env}-${inboxId}.db3` without the `./` prefix and with the environment included. Users following this example will pass a non-existent path to `backupXmtpDatabase`, causing `exportDb` to fail.

Comment on lines +996 to +1015
false // allowInboxReassign - set to true to reassign from another inbox
);

// Step 2: Sign with the NEW account's wallet
const newAccountSafeSigner = toSafeSigner(newAccountWalletSigner);

// Step 3: Apply the signature
await client.unsafe_applySignatureRequest(newAccountSafeSigner, signatureRequestId);
```

```js [Node]
import { IdentifierKind } from "@xmtp/node-sdk";

// Step 1: Generate the signature request for adding an account
const signatureRequest = await client.unsafe_addAccountSignatureRequest(
{
kind: IdentifierKind.Ethereum,
identifier: "0xNEW_ACCOUNT_ADDRESS",
},
false // allowInboxReassign - set to true to reassign from another inbox
Copy link

Choose a reason for hiding this comment

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

🟡 Medium core-messaging/manage-inboxes.mdx:996

The "Add account signature request" examples pass false for allowInboxReassign, but the SDK implementations throw InboxReassignError when this parameter is false. Developers following these examples will get an immediate error. The parameter should be true for the code to function, or the documentation should clarify that false only works when the account has no existing inbox assignment.

-    false // allowInboxReassign - set to true to reassign from another inbox
+    true // allowInboxReassign - set to false only if the account has no existing inbox
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file docs/pages/chat-apps/core-messaging/manage-inboxes.mdx around lines 996-1015:

The "Add account signature request" examples pass `false` for `allowInboxReassign`, but the SDK implementations throw `InboxReassignError` when this parameter is `false`. Developers following these examples will get an immediate error. The parameter should be `true` for the code to function, or the documentation should clarify that `false` only works when the account has no existing inbox assignment.

for (const dm of dms) {
const duplicates = await dm.duplicateDms();
if (duplicates.length > 0) {
console.log(`DM with ${dm.peerInboxId} has ${duplicates.length} underlying duplicate(s)`);
Copy link

Choose a reason for hiding this comment

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

🟠 High chat-apps/debug-your-app.mdx:169

The Browser SDK example logs dm.peerInboxId as a property, but in the Browser SDK it's defined as async peerInboxId() — a method returning Promise<string>. As written, console.log outputs [object Promise] instead of the inbox ID. Consider using await dm.peerInboxId().

-    console.log(`DM with ${dm.peerInboxId} has ${duplicates.length} underlying duplicate(s)`);
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file docs/pages/chat-apps/debug-your-app.mdx around line 169:

The Browser SDK example logs `dm.peerInboxId` as a property, but in the Browser SDK it's defined as `async peerInboxId()` — a method returning `Promise<string>`. As written, `console.log` outputs `[object Promise]` instead of the inbox ID. Consider using `await dm.peerInboxId()`.

Comment on lines +346 to +359
```js [Browser]
// Get installation IDs from inbox state
const inboxState = await client.preferences.fetchInboxState();
const installationIds = inboxState.installations.map(i => i.id);

// Check key package statuses for installations
const statuses = await client.fetchKeyPackageStatuses(installationIds);

for (const status of statuses) {
console.log("Installation:", status.installationId);
console.log("Key package valid:", status.isValid);
console.log("Lifetime remaining:", status.lifetimeNs);
}
```
Copy link

Choose a reason for hiding this comment

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

🟠 High core-messaging/manage-inboxes.mdx:346

The Browser and Node SDK examples for fetchKeyPackageStatuses incorrectly iterate over the result and access non-existent properties. fetchKeyPackageStatuses returns a Map<string, KeyPackageStatus> (Browser) or plain object (Node), not an array. Using for (const status of statuses) yields [key, value] tuples in Browser (not values) and throws a TypeError in Node since objects aren't iterable. Additionally, status.installationId, status.isValid, and status.lifetimeNs don't exist on KeyPackageStatus — the actual properties are lifetime (with notBefore/notAfter) and validationError.

-for (const status of statuses) {
-  console.log("Installation:", status.installationId);
-  console.log("Key package valid:", status.isValid);
-  console.log("Lifetime remaining:", status.lifetimeNs);
+for (const [installationId, status] of statuses) {
+  console.log("Installation:", installationId);
+  console.log("Lifetime:", status.lifetime);
+  console.log("Validation error:", status.validationError);
 }
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file docs/pages/chat-apps/core-messaging/manage-inboxes.mdx around lines 346-359:

The Browser and Node SDK examples for `fetchKeyPackageStatuses` incorrectly iterate over the result and access non-existent properties. `fetchKeyPackageStatuses` returns a `Map<string, KeyPackageStatus>` (Browser) or plain object (Node), not an array. Using `for (const status of statuses)` yields `[key, value]` tuples in Browser (not values) and throws a TypeError in Node since objects aren't iterable. Additionally, `status.installationId`, `status.isValid`, and `status.lifetimeNs` don't exist on `KeyPackageStatus` — the actual properties are `lifetime` (with `notBefore`/`notAfter`) and `validationError`.

Comment on lines +602 to +615
const inboxId = await getInboxIdForIdentifier(
{
kind: IdentifierKind.Ethereum,
identifier: "0x1234567890abcdef1234567890abcdef12345678",
},
"production" // optional, defaults to "dev"
);

if (inboxId) {
console.log("Found inbox ID:", inboxId);
} else {
console.log("This address is not registered with XMTP");
}
```
Copy link

Choose a reason for hiding this comment

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

🟠 High core-messaging/manage-inboxes.mdx:602

The documentation for getInboxIdForIdentifier uses the wrong function signature: it shows the identifier as the first argument and an environment string as the second, but the actual SDK requires a Backend object first and the Identifier second. Developers following this example will pass arguments in the wrong order and format, causing type errors or runtime failures. Consider updating the examples to create a Backend via createBackend({ env: "production" }) and pass it as the first argument.

-```js [Browser]
-import { getInboxIdForIdentifier, IdentifierKind } from "@xmtp/browser-sdk";
+
+```js [Browser]
+import { getInboxIdForIdentifier, IdentifierKind, createBackend } from "@xmtp/browser-sdk";
 
 // Look up the inbox ID for an Ethereum address
 const inboxId = await getInboxIdForIdentifier(
-  {
-    kind: IdentifierKind.Ethereum,
-    identifier: "0x1234567890abcdef1234567890abcdef12345678",
-  },
-  "production" // optional, defaults to "dev"
+  createBackend({ env: "production" }),
+  {
+    kind: IdentifierKind.Ethereum,
+    identifier: "0x1234567890abcdef1234567890abcdef12345678",
+  }
 );
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file docs/pages/chat-apps/core-messaging/manage-inboxes.mdx around lines 602-615:

The documentation for `getInboxIdForIdentifier` uses the wrong function signature: it shows the identifier as the first argument and an environment string as the second, but the actual SDK requires a `Backend` object first and the `Identifier` second. Developers following this example will pass arguments in the wrong order and format, causing type errors or runtime failures. Consider updating the examples to create a `Backend` via `createBackend({ env: "production" })` and pass it as the first argument.

const signatureBytes = await yourWallet.signMessage(signatureText);

// Step 3: Add the signature to the request
client.unsafe_addSignature(signatureRequest, signatureBytes);
Copy link

Choose a reason for hiding this comment

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

🟠 High core-messaging/manage-inboxes.mdx:931

The Node SDK unsafe_addSignature examples pass raw signatureBytes (a Uint8Array) as the second argument, but the actual API expects a Signer object with type, signMessage, and getIdentifier properties. When the SDK internally calls finalSigner.signMessage() and finalSigner.getIdentifier(), it will throw a runtime error because Uint8Array has no such methods. The correct pattern is to pass the wallet signer object (e.g., yourWalletSigner) directly without pre-signing.

-// Step 3: Add the signature to the request
-client.unsafe_addSignature(signatureRequest, signatureBytes);
+// Step 3: Add the signature to the request
+client.unsafe_addSignature(signatureRequest, yourWalletSigner);
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file docs/pages/chat-apps/core-messaging/manage-inboxes.mdx around line 931:

The Node SDK `unsafe_addSignature` examples pass raw `signatureBytes` (a `Uint8Array`) as the second argument, but the actual API expects a `Signer` object with `type`, `signMessage`, and `getIdentifier` properties. When the SDK internally calls `finalSigner.signMessage()` and `finalSigner.getIdentifier()`, it will throw a runtime error because `Uint8Array` has no such methods. The correct pattern is to pass the wallet signer object (e.g., `yourWalletSigner`) directly without pre-signing.

Comment on lines +391 to +407
```kotlin [Kotlin]
// Get installation IDs from inbox state
val inboxState = client.inboxState(true)
val installationIds = inboxState.installations.map { it.id }

// Check key package statuses for installations (static method)
val statuses = Client.keyPackageStatusesForInstallationIds(
installationIds.map { it.toByteArray() },
client.getXmtpApiClient()
)

statuses.forEach { (installationId, status) ->
println("Installation: $installationId")
println("Lifetime: ${status.lifetime}")
println("Validation error: ${status.validationError}")
}
```
Copy link

Choose a reason for hiding this comment

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

🟡 Medium core-messaging/manage-inboxes.mdx:391

The Kotlin SDK example passes installationIds.map { it.toByteArray() } to Client.keyPackageStatusesForInstallationIds, but the API expects List<String> (hex strings), not List<ByteArray>. The example also calls client.getXmtpApiClient(), which does not exist — the actual parameter should be ClientOptions.Api(...). This code will not compile.

```kotlin [Kotlin]
 // Get installation IDs from inbox state
 val inboxState = client.inboxState(true)
 val installationIds = inboxState.installations.map { it.id }
 
 // Check key package statuses for installations (static method)
 val statuses = Client.keyPackageStatusesForInstallationIds(
-    installationIds.map { it.toByteArray() },
-    client.getXmtpApiClient()
+    installationIds,
+    ClientOptions.Api(...)
 )
 
 statuses.forEach { (installationId, status) ->
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file docs/pages/chat-apps/core-messaging/manage-inboxes.mdx around lines 391-407:

The Kotlin SDK example passes `installationIds.map { it.toByteArray() }` to `Client.keyPackageStatusesForInstallationIds`, but the API expects `List<String>` (hex strings), not `List<ByteArray>`. The example also calls `client.getXmtpApiClient()`, which does not exist — the actual parameter should be `ClientOptions.Api(...)`. This code will not compile.

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.

2 participants