Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ee58534
chore: rename bsky module to feed and update imports
MathurAditya724 Jan 20, 2025
f4d8017
chore(client): add path mapping for @tsky/lexicons in tsconfig
MathurAditya724 Jan 20, 2025
f664762
chore(client): renamed the test file for feed
MathurAditya724 Jan 20, 2025
dc2e1b1
chore(client): added the paginator under utils
MathurAditya724 Jan 20, 2025
cda241a
chore(client): remove paginator export from tsky module
MathurAditya724 Jan 20, 2025
75838f7
chore(client): added manager
MathurAditya724 Jan 20, 2025
cd71e1b
chore(client): update Manager to accept options and integrate with Tsky
MathurAditya724 Jan 20, 2025
42622f0
chore: renamed manager to auth
MathurAditya724 Jan 20, 2025
c010241
chore: updated imports for auth
MathurAditya724 Jan 20, 2025
dada011
chore: restructured the bsky class
MathurAditya724 Jan 20, 2025
b813dea
chore: made client prop private
MathurAditya724 Jan 21, 2025
c7917f9
feat(client): added preference class
MathurAditya724 Jan 21, 2025
c296086
refactor(client): simplify client initialization and update feed tests
MathurAditya724 Jan 21, 2025
8d87378
chore(client): shifted profile in user class and added tests
MathurAditya724 Jan 21, 2025
211fcb6
feat(client): added feat generator
MathurAditya724 Jan 21, 2025
7ce0093
feat(client): added actor class
MathurAditya724 Jan 21, 2025
bc5b043
fix(client): added more props in the actor class
MathurAditya724 Jan 21, 2025
61ee237
feat(client): added the remaining modules
MathurAditya724 Jan 21, 2025
06573bb
chore: minor changes
MathurAditya724 Jan 21, 2025
b9a7237
chore: updated lockfile
MathurAditya724 Jan 21, 2025
88b0c22
fix: corrected the typo
MathurAditya724 Jan 22, 2025
2fc985a
chore: corrected the imports
MathurAditya724 Jan 22, 2025
a682320
fix: updated the mute and unmute api (#48)
MathurAditya724 Jan 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,24 @@
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist"],
"files": [
"dist"
],
"scripts": {
"dev": "pkgroll --watch",
"build": "pkgroll",
"build": "pkgroll --minify",
"test": "vitest",
"test:typescript": "tsc --noEmit"
},
"dependencies": {
"@atcute/client": "^2.0.6",
"@tsky/lexicons": "workspace:*"
"@atcute/client": "^2.0.6"
},
"devDependencies": {
"@tsky/lexicons": "workspace:*",
"globals": "^15.12.0",
"pkgroll": "^2.5.1",
"tsx": "^4.19.2",
"typescript": "^5.7.2",
"vitest": "^2.1.6"
}
}
}
45 changes: 45 additions & 0 deletions packages/client/src/auth/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
type AtpSessionData,
CredentialManager,
type CredentialManagerOptions,
} from '@atcute/client';

export class Auth {
manager: CredentialManager;
sessions: Map<string, AtpSessionData> = new Map();

constructor(options?: CredentialManagerOptions) {
this.manager = new CredentialManager(
options ?? { service: 'https://bsky.social' },
);
}

async login(identifier: string, password: string) {
const session = await this.manager.login({
identifier,
password,
});

this.sessions.set(session.did, session);

return session;
}

async switch(did: string) {
const session = this.sessions.get(did);

if (!session) {
throw new Error('Session not found');
}

return await this.manager.resume(session);
}

logout(did: string) {
this.sessions.delete(did);
}

get currentSession() {
return this.manager.session;
}
}
1 change: 1 addition & 0 deletions packages/client/src/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './auth';
142 changes: 142 additions & 0 deletions packages/client/src/bsky/actor/actor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import type {
AppBskyActorDefs,
AppBskyFeedGetAuthorFeed,
} from '@tsky/lexicons';
import type { Client } from '~/tsky/client';
import type { RPCOptions } from '~/types';
import { Paginator } from '~/utils';

export class Actor {
client: Client;
identifier: string;

constructor(client: Client, identifier: string) {
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;
}

/**
* Get a list of starter packs created by the 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 },
...options,
});

return res.data;
});
}

/**
* Enumerates accounts which follow a specified account (actor).
*/
followers(limit?: number, options: RPCOptions = {}) {
return Paginator.init(async (cursor) => {
const res = await this.client.get('app.bsky.graph.getFollowers', {
params: {
cursor,
actor: this.identifier,
limit,
},
...options,
});

return res.data;
});
}

/**
* Enumerates accounts which a specified account (actor) follows.
*/
follows(limit?: number, options: RPCOptions = {}) {
return Paginator.init(async (cursor) => {
const res = await this.client.get('app.bsky.graph.getFollows', {
params: {
cursor,
actor: this.identifier,
limit,
},
...options,
});

return res.data;
});
}

/**
* Enumerates the lists created by a specified account (actor).
*/
lists(limit?: number, options: RPCOptions = {}) {
return Paginator.init(async (cursor) => {
const res = await this.client.get('app.bsky.graph.getLists', {
params: {
cursor,
actor: this.identifier,
limit,
},
...options,
});

return res.data;
});
}

/**
* Enumerates public relationships between one account, and a list of other accounts. Does not require auth.
*/
async relationships(others?: string[], options?: RPCOptions) {
const res = await this.client.get('app.bsky.graph.getRelationships', {
params: {
actor: this.identifier,
others,
},
...options,
});

return res.data;
}

/**
* Get a view of an actor's 'author feed' (post and reposts by the author). Does not require auth.
*/
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 },
...options,
});

return res.data;
});
}

/**
* Get a list of feeds (feed generator records) created by the actor (in the actor's repo).
*/
feed(
params?: Omit<AppBskyFeedGetAuthorFeed.Params, 'actor'>,
options?: RPCOptions,
) {
return Paginator.init(async (cursor) => {
const res = await this.client.get('app.bsky.feed.getAuthorFeed', {
params: { cursor, ...params, actor: this.identifier },
...options,
});

return res.data;
});
}
}
1 change: 1 addition & 0 deletions packages/client/src/bsky/actor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './actor';
20 changes: 20 additions & 0 deletions packages/client/src/bsky/bsky.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Feed } from '~/bsky/feed';
import type { Client } from '~/tsky/client';
import { Actor } from './actor';
import { List } from './list';

export class Bsky {
constructor(private client: Client) {}

actor(identifier: string) {
return new Actor(this.client, identifier);
}

list(uri: string) {
return new List(this.client, uri);
}

get feed() {
return new Feed(this.client);
}
}
44 changes: 44 additions & 0 deletions packages/client/src/bsky/feed/feed.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, expect, it } from 'vitest';
import { Tsky } from '~/index';

const TEST_CREDENTIALS = {
alice: {
handle: 'alice.tsky.dev',
did: 'did:plc:jguhdmnjclquqf5lsvkyxqy3',
password: 'alice_and_bob',
},
bob: {
handle: 'bob.tsky.dev',
did: 'did:plc:2ig7akkyfq256j42uxvc4g2h',
password: 'alice_and_bob',
},
};

async function getAliceTsky() {
const tsky = new Tsky();

await tsky.auth.login(
TEST_CREDENTIALS.alice.handle,
TEST_CREDENTIALS.alice.password,
);

return tsky;
}

describe('feed', () => {
it('.getFeed()', async () => {
const tsky = await getAliceTsky();
const paginator = await tsky.bsky.feed.get({
// "Birds! 🦉" custom feed
// - https://bsky.app/profile/daryllmarie.bsky.social/feed/aaagllxbcbsje
feed: 'at://did:plc:ffkgesg3jsv2j7aagkzrtcvt/app.bsky.feed.generator/aaagllxbcbsje',
limit: 30,
});
expect(paginator).toBeDefined();
expect(paginator.values).toBeDefined();
expect(paginator.values).toBeInstanceOf(Array);
expect(paginator.values.length).toBe(1); // we should get the first page from the paginator
expect(paginator.values[0].feed.length).toBeGreaterThan(0); // we found some birds posts ;)
expect(paginator.values[0].feed[0]).toHaveProperty('post');
});
});
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import type {
AppBskyFeedGetFeed,
AppBskyFeedGetTimeline,
AppBskyFeedSendInteractions,
} from '@tsky/lexicons';
import type { Client } from '~/tsky/client';
import { Paginator } from '~/tsky/paginator';
import type { RPCOptions } from '~/types';
import { Paginator } from '~/utils';
import { FeedGenerator } from './generator';

export class Feed {
constructor(private client: Client) {}

/**
* Get a hydrated feed from an actor's selected feed generator. Implemented by App View.
*/
async getFeed(
async get(
params: AppBskyFeedGetFeed.Params,
options?: AppBskyFeedGetFeed.Input,
): Promise<Paginator<AppBskyFeedGetFeed.Output>> {
Expand All @@ -29,22 +31,21 @@ export class Feed {
}

/**
* Get a view of the requesting account's home timeline. This is expected to be some form of reverse-chronological feed.
* Send information about interactions with feed items back to the feed generator that served them.
*/
getTimeline(
params: AppBskyFeedGetTimeline.Params,
options?: AppBskyFeedGetTimeline.Input,
): Promise<Paginator<AppBskyFeedGetTimeline.Output>> {
return Paginator.init(async (cursor) => {
const res = await this.client.get('app.bsky.feed.getTimeline', {
...(options ?? {}),
params: {
cursor,
...params,
},
});

return res.data;
async sendInteractions(
interactions: AppBskyFeedSendInteractions.Input['interactions'],
options: RPCOptions = {},
) {
const res = await this.client.call('app.bsky.feed.sendInteractions', {
data: { interactions },
...options,
});

return res.data;
}

generator() {
return new FeedGenerator(this.client);
}
}
Loading
Loading