IFriendsManager
Interface: IFriendsManager
Defined in: api/friends/interface.ts:48
Friends domain manager — all friend-graph operations live here.
All UUIDs are hyphenated string UserId values. Mutations
resolve void on success; reads return consumer-shape types
(Friend, User, ReceivedRequest,
SentRequest) — never bundle protobuf shapes.
Remarks
Reads share a single underlying IFriendsManager.snapshot.
IFriendsManager.list, IFriendsManager.receivedRequests,
and IFriendsManager.sentRequests are slim accessors that
project the relevant slice. One subscription method
(IFriendsManager.onChange) fires whenever any of the three
slots changes; it returns an Unsubscribe thunk that's
idempotent.
The interface is composed from three thematic groupings:
- IFriendsMutations —
sendRequest,remove,block,unblock,acceptRequest,rejectRequest. - IFriendsReads —
list,receivedRequests,sentRequests,snapshot,refresh,search,getUsers. - IFriendsSubscriptions —
onChange,on.
See
Extends
IFriendsMutations.IFriendsReads.IFriendsSubscriptions
Methods
acceptRequest()
acceptRequest(userId: string): Promise<void>;Defined in: api/friends/interface-mutations.ts:118
Accept an incoming friend request.
Equivalent on the wire to IFriendsMutations.sendRequest with
source: ADDED_BY_ADDED_ME_BACK — the SPA path. Surfaced as a named
verb because the inbox flow has its own consumer mental model;
acceptRequest(req.fromUserId) reads more clearly than
sendRequest(req.fromUserId, { source: 4 }).
Parameters
| Parameter | Type | Description |
|---|---|---|
userId | string | Hyphenated UUID of the requester whose request to accept (the fromUserId field on a ReceivedRequest). |
Returns
Promise<void>
Example
for (const req of await client.friends.receivedRequests()) {
await client.friends.acceptRequest(req.fromUserId);
}Inherited from
IFriendsMutations.acceptRequestblock()
block(userId: string): Promise<void>;Defined in: api/friends/interface-mutations.ts:90
Block a user — also removes any existing friend link.
Parameters
| Parameter | Type | Description |
|---|---|---|
userId | string | Hyphenated UUID of the user to block. |
Returns
Promise<void>
Example
await client.friends.block(userId);Inherited from
IFriendsMutations.blockgetUsers()
getUsers(userIds: string[], opts?: {
refresh?: boolean;
}): Promise<FriendsUser[]>;Defined in: api/friends/interface-reads.ts:134
Resolve a list of user IDs to User records (username + display name).
Cache-first: each ID is looked up in the bundle's
state.user.publicUsers cache; only IDs that miss are sent to Snap's
GetSnapchatterPublicInfo. Pass { refresh: true } to force a
fresh RPC for every ID.
Parameters
| Parameter | Type | Description |
|---|---|---|
userIds | string[] | Hyphenated UUIDs to resolve. |
opts? | { refresh?: boolean; } | refresh: true re-fetches all IDs, ignoring the cache. Defaults to cache-first. |
opts.refresh? | boolean | - |
Returns
Resolved User records in the same order as userIds.
IDs the server returned no record for (deleted accounts, blocks)
appear with notFound: true.
Examples
Look up a single ID via array destructuring:
const [user] = await client.friends.getUsers([id]);
if (user?.notFound) console.log("account is gone");Backfill usernames from a freshly-synced friends list:
const friends = await client.friends.list();
const users = await client.friends.getUsers(friends.map((f) => f.userId));Inherited from
IFriendsReads.getUserslist()
list(): Promise<Friend[]>;Defined in: api/friends/interface-reads.ts:30
All friends in the logged-in user's social graph (excluding self).
Returns
Mutually-confirmed friends as Friend records.
Example
const friends = await client.friends.list();
for (const f of friends) console.log(f.username);Inherited from
IFriendsReads.liston()
on<K>(
event: K,
cb: FriendsEvents[K],
opts?: {
signal?: AbortSignal;
}): Subscription;Defined in: api/friends/interface-subscriptions.ts:70
Subscribe to a typed friends event. Returns a Subscription
— call it to unsubscribe, or use sub.signal to tie the
subscription's life to anything that takes an AbortSignal.
Type Parameters
| Type Parameter |
|---|
K extends keyof FriendsEvents |
Parameters
| Parameter | Type | Description |
|---|---|---|
event | K | Event name from FriendsEvents. |
cb | FriendsEvents[K] | Callback fired with the event payload (type narrows on event). |
opts? | { signal?: AbortSignal; } | Optional signal — when the passed AbortSignal aborts, the subscription is torn down automatically. The returned sub.signal reflects the combined lifetime (fires on either path). |
opts.signal? | AbortSignal | - |
Returns
A Subscription — a callable unsubscribe thunk with
.signal attached.
Examples
const sub = client.friends.on("request:received", (req) => {
console.log(`new request from ${req.fromUsername}`);
});
// ...later
sub();Tie multiple subscriptions to one external AbortController:
const ctrl = new AbortController();
client.friends.on("request:received", onReq, { signal: ctrl.signal });
client.friends.on("change", onChange, { signal: ctrl.signal });
ctrl.abort(); // tears down bothInherited from
IFriendsSubscriptions.ononChange()
onChange(cb: (snap: FriendsSnapshot) => void): Unsubscribe;Defined in: api/friends/interface-subscriptions.ts:36
Fire cb whenever any part of the friend graph changes — mutuals,
incoming requests, or outgoing requests.
The callback receives a full FriendsSnapshot reflecting the
new state. Initial state is NOT replayed — call
snapshot() once after subscribing if you need a baseline.
Parameters
| Parameter | Type | Description |
|---|---|---|
cb | (snap: FriendsSnapshot) => void | Subscriber invoked with the latest snapshot on every relevant change. |
Returns
An Unsubscribe thunk; idempotent on repeat calls.
Example
const unsub = client.friends.onChange((snap) => {
console.log(`mutuals=${snap.mutuals.length}`);
});
// ...later
unsub();Inherited from
IFriendsSubscriptions.onChangereceivedRequests()
receivedRequests(): Promise<ReceivedRequest[]>;Defined in: api/friends/interface-reads.ts:38
All pending received friend requests.
Returns
Inbound ReceivedRequest records waiting for accept / reject / ignore.
Inherited from
IFriendsReads.receivedRequestsrefresh()
refresh(): Promise<void>;Defined in: api/friends/interface-reads.ts:86
Force an explicit re-sync from the server — pulls the latest mutuals
- outgoing requests (via
SyncFriendData) AND incoming requests (viaIncomingFriendSync).
Returns
Promise<void>
Remarks
The bundle does NOT auto-poll for fresh state — the SPA's React layer
normally drives that cadence, and we don't load React. So consumers
who want event subscriptions like
IFriendsSubscriptions.on("request:received") to actually fire
must drive their own refresh cadence. Common patterns:
- Call
refresh()in asetInterval(every 10–30s for inbox-style monitoring, every 60s+ for less time-sensitive use cases). - Call
refresh()on demand right before a snapshot read.
Best-effort — failures are swallowed (the existing userSlice.syncFriends
pattern). Subsequent reads return whatever is in cache.
Example
setInterval(() => client.friends.refresh(), 30_000);
client.friends.on("request:received", (req) => { ... });Inherited from
IFriendsReads.refreshrejectRequest()
rejectRequest(userId: string): Promise<void>;Defined in: api/friends/interface-mutations.ts:135
Reject (ignore) an incoming friend request.
Maps to Snap's IgnoreFriends RPC — the same path the SPA's
"Ignore" button uses. Once rejected, the request disappears from
IFriendsReads.receivedRequests.
Parameters
| Parameter | Type | Description |
|---|---|---|
userId | string | Hyphenated UUID of the requester whose request to reject (the fromUserId field on a ReceivedRequest). |
Returns
Promise<void>
Example
await client.friends.rejectRequest(req.fromUserId);Inherited from
IFriendsMutations.rejectRequestremove()
remove(userId: string): Promise<void>;Defined in: api/friends/interface-mutations.ts:78
Remove a friend from the social graph.
Parameters
| Parameter | Type | Description |
|---|---|---|
userId | string | Hyphenated UUID of the friend to remove. |
Returns
Promise<void>
Deprecated
Snap's web backend silently rejects this RPC. The call
goes through (HTTP 200, gRPC status 0), but the friendship is NOT
actually severed server-side. Calling this is a no-op from web.snapchat.com.
Kept on the interface for API symmetry and future mobile-emulation
support; do not depend on it for production logic today.
Remarks
Why this doesn't work: Snap's web SPA itself doesn't expose "Remove Friend" anywhere in its UI — friend mutations like remove, block, and unblock are restricted to the mobile clients (iOS / Android) and the server enforces this at the policy layer. We verified empirically:
- The request reaches the server:
RemoveFriends → 200 grpc=0. - The body encodes correctly (we tested with empty
pageSessionId, a random UUID, and the realsc-a-noncesession cookie value — all yield the same outcome). - The bundle's chat module never calls
RemoveFriendsfrom any code path — the SPA's right-click menu on a friend chat shows onlyMessage Notifications,Delete Chats,Clear from Chat Feed. - After the call,
friends.list()still returns the supposedly-removed account as mutual on both sides (we tested symmetric removes too).
What does work: IFriendsMutations.sendRequest (web supports AddFriends), IFriendsMutations.acceptRequest, IFriendsMutations.rejectRequest.
Workarounds: none from web. To actually unfriend an account, the user must do it from the official mobile app.
Example
// This will resolve without throwing, but the friendship persists:
await client.friends.remove(userId);Inherited from
IFriendsMutations.removesearch()
search(query: string): Promise<FriendsUser[]>;Defined in: api/friends/interface-reads.ts:102
Search Snap's user index by username / display-name fragment.
Parameters
| Parameter | Type | Description |
|---|---|---|
query | string | Free-text query — Snap's "Add Friends" search box matches both usernames and display names, with prefix and substring weighting. |
Returns
A list of matching User records. Empty when query
is empty or no users match.
Example
const users = await client.friends.search("alice");Inherited from
IFriendsReads.searchsendRequest()
sendRequest(userId: string, opts?: {
source?: FriendSource;
}): Promise<void>;Defined in: api/friends/interface-mutations.ts:36
Send a friend request / add a user to the friend list.
Resolves once the server acknowledges.
Parameters
| Parameter | Type | Description |
|---|---|---|
userId | string | Hyphenated UUID of the user to add. |
opts? | { source?: FriendSource; } | Advanced overrides; ignore for the common case. The one knob is source — anti-spam attribution context (mirrors what the SPA stamps on the request to identify which UI surface triggered the add). Defaults to FriendSource.ADDED_BY_USERNAME. Override only if you're explicitly mimicking a different UX flow (QR-code add, deep-link add, etc.). |
opts.source? | FriendSource | - |
Returns
Promise<void>
Examples
await client.friends.sendRequest("eabd1d89-239a-4f7b-bbcc-0ae3b26c5202");Override the attribution source:
import { FriendSource } from "@snapcap/native";
await client.friends.sendRequest(userId, { source: FriendSource.ADDED_BY_SEARCH });Inherited from
IFriendsMutations.sendRequestsentRequests()
sentRequests(): Promise<SentRequest[]>;Defined in: api/friends/interface-reads.ts:46
All pending sent friend requests (the logged-in user's adds waiting for the recipient to accept).
Returns
Outbound SentRequest records.
Inherited from
IFriendsReads.sentRequestssnapshot()
snapshot(): Promise<FriendsSnapshot>;Defined in: api/friends/interface-reads.ts:59
Canonical point-in-time view of the friend graph — mutuals + pending requests in both directions.
Returns
A FriendsSnapshot with all three slots populated.
Remarks
The split read accessors (IFriendsReads.list, IFriendsReads.receivedRequests, IFriendsReads.sentRequests) all project from this.
Inherited from
IFriendsReads.snapshotunblock()
unblock(userId: string): Promise<void>;Defined in: api/friends/interface-mutations.ts:97
Unblock a previously-blocked user.
Parameters
| Parameter | Type | Description |
|---|---|---|
userId | string | Hyphenated UUID of the user to unblock. |
Returns
Promise<void>
Inherited from
IFriendsMutations.unblock