Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(client): fix type errors of Client's methods #76

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"nano-staged": "^0.8.0"
"nano-staged": "^0.8.0",
"rimraf": "^6.0.1"
},
"nano-staged": {
"*.{js,ts,cjs,mjs,json}": ["biome check --write --"]
"*.{js,ts,cjs,mjs,json}": [
"biome check --write --"
]
}
}
137 changes: 112 additions & 25 deletions packages/client/src/actor/actor.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
import type {
AppBskyActorDefs,
AppBskyFeedGetAuthorFeed,
AppBskyGraphDefs,
At,
ComAtprotoLabelDefs,
ComAtprotoRepoStrongRef,
} from '@tsky/lexicons';
import type { Client } from '~/agent/client';
import type { RPCOptions } from '~/types';
import { Paginator } from '~/utils';

export class Actor {
client: Client;
identifier: string;
did: At.DID;

constructor(client: Client, identifier: string) {
constructor(client: Client, did: At.DID) {
this.client = client;
this.identifier = identifier;
}

/**
* Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth.
*/
async profile(): Promise<AppBskyActorDefs.ProfileViewDetailed> {
const res = await this.client.get('app.bsky.actor.getProfile', {
params: { actor: this.identifier },
});

return res.data;
this.did = did;
}

/**
Expand All @@ -32,7 +25,7 @@ export class Actor {
starterPacks(limit?: number, options: RPCOptions = {}) {
return Paginator.init(async (cursor) => {
const res = await this.client.get('app.bsky.graph.getActorStarterPacks', {
params: { cursor, actor: this.identifier, limit },
params: { cursor, actor: this.did, limit },
...options,
});

Expand All @@ -48,13 +41,19 @@ export class Actor {
const res = await this.client.get('app.bsky.graph.getFollowers', {
params: {
cursor,
actor: this.identifier,
actor: this.did,
limit,
},
...options,
});

return res.data;
return {
...res.data,
subject: new ActorProfile(this.client, res.data.subject),
followers: res.data.followers.map(
(follower) => new ActorProfile(this.client, follower),
),
};
});
}

Expand All @@ -66,13 +65,19 @@ export class Actor {
const res = await this.client.get('app.bsky.graph.getFollows', {
params: {
cursor,
actor: this.identifier,
actor: this.did,
limit,
},
...options,
});

return res.data;
return {
...res.data,
subject: new ActorProfile(this.client, res.data.subject),
follows: res.data.follows.map(
(follow) => new ActorProfile(this.client, follow),
),
};
});
}

Expand All @@ -84,13 +89,17 @@ export class Actor {
const res = await this.client.get('app.bsky.graph.getLists', {
params: {
cursor,
actor: this.identifier,
actor: this.did,
limit,
},
...options,
});

return res.data;
return {
...res.data,
// TODO: Solve this
// lists: res.data.lists.map((list) => new List(this.client, list)),
};
});
}

Expand All @@ -100,13 +109,18 @@ export class Actor {
async relationships(others?: string[], options?: RPCOptions) {
const res = await this.client.get('app.bsky.graph.getRelationships', {
params: {
actor: this.identifier,
actor: this.did,
others,
},
...options,
});

return res.data;
return {
...res.data,
actor: res.data.actor
? new Actor(this.client, res.data.actor)
: undefined,
};
}

/**
Expand All @@ -115,7 +129,7 @@ export class Actor {
feeds(limit?: number, options?: RPCOptions) {
return Paginator.init(async (cursor) => {
const res = await this.client.get('app.bsky.feed.getActorFeeds', {
params: { cursor, actor: this.identifier, limit },
params: { cursor, actor: this.did, limit },
...options,
});

Expand All @@ -132,11 +146,84 @@ export class Actor {
) {
return Paginator.init(async (cursor) => {
const res = await this.client.get('app.bsky.feed.getAuthorFeed', {
params: { cursor, ...params, actor: this.identifier },
params: { cursor, ...params, actor: this.did },
...options,
});

return res.data;
});
}
}

// TODO: we can give this a better name
export class ActorWithProfileFunction extends Actor {
async profile() {
const data = await this.client
.get('app.bsky.actor.getProfile', {
params: { actor: this.did },
})
.then((res) => res.data);

if (
data.viewer?.knownFollowers?.followers &&
data.viewer?.knownFollowers?.followers.length > 0
) {
data.viewer.knownFollowers.followers =
data.viewer.knownFollowers.followers.map(
(follower) => new BasicActorProfile(this.client, follower),
);
}

return data;
}
}

export class BasicActorProfile
extends Actor
implements AppBskyActorDefs.ProfileViewBasic
{
// @ts-expect-error - We added this property with Object.assign
handle: string;
associated?: AppBskyActorDefs.ProfileAssociated;
avatar?: string;
createdAt?: string;
displayName?: string;
labels?: ComAtprotoLabelDefs.Label[];
viewer?: AppBskyActorDefs.ViewerState;
$type?: string;

constructor(client: Client, actor: AppBskyActorDefs.ProfileViewBasic) {
super(client, actor.did);
Object.assign(this, actor);
}
}

export class ActorProfile
extends BasicActorProfile
implements AppBskyActorDefs.ProfileView
{
description?: string;
indexedAt?: string;

constructor(client: Client, actor: AppBskyActorDefs.ProfileViewDetailed) {
super(client, actor);
Object.assign(this, actor);
}
}

export class DetailedActorProfile
extends ActorProfile
implements AppBskyActorDefs.ProfileViewDetailed
{
banner?: string;
followersCount?: number;
followsCount?: number;
joinedViaStarterPack?: AppBskyGraphDefs.StarterPackViewBasic;
pinnedPost?: ComAtprotoRepoStrongRef.Main;
postsCount?: number;

constructor(client: Client, actor: AppBskyActorDefs.ProfileViewDetailed) {
super(client, actor);
Object.assign(this, actor);
}
}
63 changes: 53 additions & 10 deletions packages/client/src/agent/agent.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
import { type CredentialManager, XRPC } from '@atcute/client';
import type { Queries } from '@tsky/lexicons';
import { Actor } from '~/actor';
import type {
AppBskyGraphGetStarterPack,
AppBskyGraphGetStarterPacks,
At,
} from '@tsky/lexicons';
import { ActorWithProfileFunction } from '~/actor';
import { Feed } from '~/feed';
import { List } from '~/list';
import { StarterPack } from '~/starterpack';
import { Search } from '~/search';
import type { RPCOptions } from '~/types';
import { User } from '~/user';
import { Video } from '~/video';
import { Client } from './client';

export class Agent {
private client: Client<Queries>;
client: Client;

constructor(private handler: CredentialManager) {
// Initialize the client
const xrpc = new XRPC({ handler: this.handler });
this.client = new Client(xrpc);
this.client = new Client(xrpc, this.handler);
}

get session() {
return this.handler.session;
}

actor(identifier: string) {
return new Actor(this.client, identifier);
/**
* Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth.
*/
async actor(identifier: At.DID): Promise<ActorWithProfileFunction> {
return new ActorWithProfileFunction(this.client, identifier);
}

list(uri: string) {
Expand All @@ -33,12 +41,16 @@ export class Agent {
return new Feed(this.client);
}

get search() {
return new Search(this.client);
}

get user() {
if (!this.session) {
throw new Error('There is no active session');
}

return new User(this.client, this.session.handle);
return new User(this.client, this.session.did);
}

get video() {
Expand All @@ -49,7 +61,38 @@ export class Agent {
return new Video(this.client);
}

get starterpack() {
return new StarterPack(this.client);
/**
* Gets a view of a starter pack.
*/
startpacks(
uri: string,
options?: RPCOptions,
): Promise<AppBskyGraphGetStarterPack.Output>;
/**
* Get views for a list of starter packs.
*/
startpacks(
uris: string[],
options?: RPCOptions,
): Promise<AppBskyGraphGetStarterPacks.Output['starterPacks']>;

async startpacks(uris: string | string[], options: RPCOptions = {}) {
if (Array.isArray(uris)) {
const res = await this.client.get('app.bsky.graph.getStarterPacks', {
params: {
uris,
},
...options,
});

return res.data.starterPacks;
}

const res = await this.client.get('app.bsky.graph.getStarterPack', {
params: { starterPack: uris },
...options,
});

return res.data;
}
}
Loading
Loading