Skip to content

Commit acafde3

Browse files
committed
refactor: remove bluesky-client from monorepo
1 parent f120baf commit acafde3

File tree

198 files changed

+96
-14237
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

198 files changed

+96
-14237
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
This monorepository contains the following projects:
44

5-
- `bluesky-client`: lightweight TypeScript API client for Bluesky
65
- [Skeetdeck](https://skeetdeck.pages.dev): Alternative web client for Bluesky with a deck interface
76
![](https://github.com/mary-ext/langit/assets/148872143/9eb9b568-397c-4c60-835c-c5101c192a47)
87

app/api/atp-schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export type * from '@externdefs/bluesky-client/atp-schema';
1+
export type * from '@externdefs/bluesky-client/lexicons';

app/api/classes/multiagent.ts

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
import { batch, createEffect, createRoot, onCleanup } from 'solid-js';
1+
import { batch, createEffect, createRoot } from 'solid-js';
22

33
import {
44
type AtpAccessJwt,
5-
type AtpLoginOptions,
65
type AtpSessionData,
7-
Agent,
8-
} from '@externdefs/bluesky-client/agent';
9-
import { decodeJwt } from '@externdefs/bluesky-client/jwt';
6+
type AuthLoginOptions,
7+
BskyAuth,
8+
BskyXRPC,
9+
} from '@externdefs/bluesky-client';
10+
import { decodeJwt } from '@externdefs/bluesky-client/utils/jwt';
1011

1112
import type { At } from '../atp-schema';
1213

1314
import { createReactiveLocalStorage } from '~/utils/storage';
1415

15-
export interface MultiagentLoginOptions extends AtpLoginOptions {
16+
export interface MultiagentLoginOptions extends AuthLoginOptions {
1617
service: string;
1718
}
1819

@@ -37,8 +38,13 @@ interface MultiagentStorage {
3738
accounts: MultiagentAccountData[];
3839
}
3940

40-
interface AgentInstance {
41-
agent: Promise<Agent>;
41+
export interface AgentInstance {
42+
rpc: BskyXRPC;
43+
auth: BskyAuth;
44+
}
45+
46+
interface StoredAgent {
47+
instance: Promise<AgentInstance>;
4248
cleanup: () => void;
4349
}
4450

@@ -52,7 +58,7 @@ export class MultiagentError extends Error {
5258
export class Multiagent {
5359
store: MultiagentStorage;
5460

55-
#agents: Record<At.DID, AgentInstance> = {};
61+
#agents: Record<At.DID, StoredAgent> = {};
5662

5763
constructor(name: string) {
5864
const store = createReactiveLocalStorage<MultiagentStorage>(name, (version, prev) => {
@@ -110,12 +116,12 @@ export class Multiagent {
110116
* Login with a new account
111117
*/
112118
async login({ service, identifier, password }: MultiagentLoginOptions): Promise<At.DID> {
113-
const { agent, cleanup } = this.#createAgent(service);
119+
const { auth, rpc, cleanup } = this.#createAgent(service);
114120

115121
try {
116-
await agent.login({ identifier, password });
122+
await auth.login({ identifier, password });
117123

118-
const session = agent.session!;
124+
const session = auth.session!;
119125
const did = session.did;
120126

121127
const sessionJwt = decodeJwt(session.accessJwt) as AtpAccessJwt;
@@ -140,7 +146,7 @@ export class Multiagent {
140146
});
141147

142148
this.#agents[did]?.cleanup();
143-
this.#agents[did] = { agent: Promise.resolve(agent), cleanup: cleanup };
149+
this.#agents[did] = { instance: Promise.resolve({ auth, rpc }), cleanup: cleanup };
144150
return did;
145151
} catch (err) {
146152
throw new MultiagentError(`LOGIN_FAILURE`, { cause: err });
@@ -168,9 +174,9 @@ export class Multiagent {
168174
/**
169175
* Retrieve an agent associated with an account
170176
*/
171-
connect(did: At.DID): Promise<Agent> {
177+
connect(did: At.DID): Promise<AgentInstance> {
172178
if (did in this.#agents) {
173-
return this.#agents[did].agent;
179+
return this.#agents[did].instance;
174180
}
175181

176182
const $accounts = this.store.accounts;
@@ -180,12 +186,12 @@ export class Multiagent {
180186
return Promise.reject(new MultiagentError(`INVALID_ACCOUNT`));
181187
}
182188

183-
const { agent, cleanup } = this.#createAgent(data.service);
189+
const { rpc, auth, cleanup } = this.#createAgent(data.service);
184190

185-
const promise = new Promise<Agent>((resolve, reject) => {
186-
agent.resumeSession(data.session).then(
191+
const promise = new Promise<AgentInstance>((resolve, reject) => {
192+
auth.resume(data.session).then(
187193
() => {
188-
resolve(agent);
194+
resolve({ auth, rpc });
189195
},
190196
(err) => {
191197
cleanup();
@@ -196,34 +202,35 @@ export class Multiagent {
196202
);
197203
});
198204

199-
this.#agents[did] = { agent: promise, cleanup: cleanup };
205+
this.#agents[did] = { instance: promise, cleanup: cleanup };
200206
return promise;
201207
}
202208

203209
#createAgent(serviceUri: string) {
204-
const $accounts = this.store.accounts!;
205-
const agent = new Agent({ serviceUri: serviceUri });
210+
let ignore = false;
206211

207-
return {
208-
agent: agent,
209-
cleanup: createRoot((dispose) => {
210-
let ignore = false;
212+
const $accounts = this.store.accounts!;
211213

212-
onCleanup(
213-
agent.on('sessionUpdate', (session) => {
214-
const did = session!.did;
215-
const existing = $accounts.find((acc) => acc.did === did);
214+
const rpc = new BskyXRPC({ service: serviceUri });
215+
const auth = new BskyAuth(rpc, {
216+
onRefresh(session) {
217+
const did = session!.did;
218+
const existing = $accounts.find((acc) => acc.did === did);
216219

217-
if (existing) {
218-
ignore = true;
219-
batch(() => Object.assign(existing.session, session));
220-
ignore = false;
221-
}
222-
}),
223-
);
220+
if (existing) {
221+
ignore = true;
222+
batch(() => Object.assign(existing.session, session));
223+
ignore = false;
224+
}
225+
},
226+
});
224227

228+
return {
229+
rpc: rpc,
230+
auth: auth,
231+
cleanup: createRoot((dispose) => {
225232
createEffect(() => {
226-
const actual = agent.session;
233+
const actual = auth.session;
227234

228235
const did = actual?.did;
229236
const existing = $accounts.find((acc) => did && acc.did === did);

app/api/did.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type DidDocument, Agent } from '@externdefs/bluesky-client/agent';
1+
import { type DidDocument, BskyXRPC} from '@externdefs/bluesky-client'
22

33
import type { At } from './atp-schema';
44
import { APPVIEW_URL } from './globals/defaults';
@@ -16,8 +16,8 @@ export const getDidInfo = async (identifier: string): Promise<DidDocument> => {
1616
if (isDid(identifier)) {
1717
did = identifier;
1818
} else {
19-
const agent = new Agent({ serviceUri: APPVIEW_URL });
20-
const response = await agent.rpc.get('com.atproto.identity.resolveHandle', {
19+
const rpc = new BskyXRPC({ service: APPVIEW_URL });
20+
const response = await rpc.get('com.atproto.identity.resolveHandle', {
2121
params: {
2222
handle: identifier,
2323
},

app/api/queries/_did.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import type { Agent } from '@externdefs/bluesky-client/agent';
1+
import type { BskyXRPC } from '@externdefs/bluesky-client';
22

33
import type { At } from '../atp-schema';
44
import { isDid } from '../utils/misc';
55

6-
const _getDid = async (agent: Agent, actor: string, signal?: AbortSignal) => {
6+
const _getDid = async (rpc: BskyXRPC, actor: string, signal?: AbortSignal) => {
77
let did: At.DID;
88
if (isDid(actor)) {
99
did = actor;
1010
} else {
11-
const response = await agent.rpc.get('com.atproto.identity.resolveHandle', {
11+
const response = await rpc.get('com.atproto.identity.resolveHandle', {
1212
signal: signal,
1313
params: { handle: actor },
1414
});

app/api/queries/get-post-thread.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const getPostThread = async (ctx: QC<ReturnType<typeof getPostThreadKey>>
2121
const [, uid, actor, rkey, depth, height] = ctx.queryKey;
2222

2323
const agent = await multiagent.connect(uid);
24-
const did = await _getDid(agent, actor);
24+
const did = await _getDid(agent.rpc, actor);
2525

2626
const uri = `at://${did}/app.bsky.feed.post/${rkey}`;
2727
const response = await agent.rpc.get('app.bsky.feed.getPostThread', {

app/api/queries/get-timeline.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Agent } from '@externdefs/bluesky-client/agent';
1+
import { BskyXRPC } from '@externdefs/bluesky-client';
2+
23
import type { QueryFunctionContext as QC } from '@pkg/solid-query';
34

45
import { assert, mapDefined } from '~/utils/misc';
@@ -32,6 +33,7 @@ import type { FilterPreferences, LanguagePreferences } from '../types';
3233

3334
import _getDid from './_did';
3435
import { fetchPost } from './get-post';
36+
import type { AgentInstance } from '../classes/multiagent';
3537

3638
const PALOMAR_SERVICE = 'https://palomar.bsky.social';
3739

@@ -186,7 +188,7 @@ export const getTimeline = wrapInfiniteQuery(
186188
postFilter = createLabelPostFilter(timelineOpts?.moderation);
187189

188190
if (params.tab === 'posts') {
189-
const did = await _getDid(agent, params.actor);
191+
const did = await _getDid(agent.rpc, params.actor);
190192
sliceFilter = createProfileSliceFilter(did);
191193
postFilter = combine([createInvalidReplyFilter(), createLabelPostFilter(timelineOpts?.moderation)]);
192194
} else if (params.tab === 'likes' || params.tab === 'media') {
@@ -243,9 +245,9 @@ export const getTimelineLatest = async (ctx: QC<ReturnType<typeof getTimelineLat
243245

244246
// Short-circuit search timeline so that we don't go through the hydration
245247
if (params.type === 'search') {
246-
const agent = new Agent({ serviceUri: PALOMAR_SERVICE });
248+
const rpc = new BskyXRPC({ service: PALOMAR_SERVICE });
247249

248-
const response = await agent.rpc.get('app.bsky.unspecced.searchPostsSkeleton', {
250+
const response = await rpc.get('app.bsky.unspecced.searchPostsSkeleton', {
249251
signal: ctx.signal,
250252
params: {
251253
q: params.query,
@@ -268,7 +270,7 @@ export const getTimelineLatest = async (ctx: QC<ReturnType<typeof getTimelineLat
268270

269271
//// Raw fetch
270272
const fetchPage = async (
271-
agent: Agent,
273+
{ auth, rpc }: AgentInstance,
272274
params: TimelineParams,
273275
limit: number,
274276
cursor: string | undefined,
@@ -286,7 +288,7 @@ const fetchPage = async (
286288
}
287289

288290
if (type === 'home') {
289-
const response = await agent.rpc.get('app.bsky.feed.getTimeline', {
291+
const response = await rpc.get('app.bsky.feed.getTimeline', {
290292
signal: signal,
291293
headers: headers,
292294
params: {
@@ -298,7 +300,7 @@ const fetchPage = async (
298300

299301
return response.data;
300302
} else if (type === 'feed') {
301-
const response = await agent.rpc.get('app.bsky.feed.getFeed', {
303+
const response = await rpc.get('app.bsky.feed.getFeed', {
302304
signal: signal,
303305
headers: headers,
304306
params: {
@@ -310,7 +312,7 @@ const fetchPage = async (
310312

311313
return response.data;
312314
} else if (type === 'list') {
313-
const response = await agent.rpc.get('app.bsky.feed.getListFeed', {
315+
const response = await rpc.get('app.bsky.feed.getListFeed', {
314316
signal: signal,
315317
headers: headers,
316318
params: {
@@ -323,7 +325,7 @@ const fetchPage = async (
323325
return response.data;
324326
} else if (type === 'profile') {
325327
if (params.tab === 'likes') {
326-
const response = await agent.rpc.get('app.bsky.feed.getActorLikes', {
328+
const response = await rpc.get('app.bsky.feed.getActorLikes', {
327329
signal: signal,
328330
headers: headers,
329331
params: {
@@ -335,7 +337,7 @@ const fetchPage = async (
335337

336338
return response.data;
337339
} else {
338-
const response = await agent.rpc.get('app.bsky.feed.getAuthorFeed', {
340+
const response = await rpc.get('app.bsky.feed.getAuthorFeed', {
339341
signal: signal,
340342
headers: headers,
341343
params: {
@@ -354,9 +356,9 @@ const fetchPage = async (
354356
return response.data;
355357
}
356358
} else if (type === 'search') {
357-
const palomar = new Agent({ serviceUri: PALOMAR_SERVICE });
359+
const palomar = new BskyXRPC({ service: PALOMAR_SERVICE });
358360

359-
const skeleton = await palomar.rpc.get('app.bsky.unspecced.searchPostsSkeleton', {
361+
const skeleton = await palomar.get('app.bsky.unspecced.searchPostsSkeleton', {
360362
signal: signal,
361363
headers: headers,
362364
params: {
@@ -369,7 +371,7 @@ const fetchPage = async (
369371
const data = skeleton.data;
370372
const skeletons = data.posts;
371373

372-
const uid = agent.session!.did;
374+
const uid = auth.session!.did;
373375
const results = await Promise.allSettled(skeletons.map((post) => fetchPost([uid, post.uri])));
374376

375377
signal?.throwIfAborted();

app/api/richtext/composer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { XRPCError } from '@externdefs/bluesky-client/xrpc-utils';
1+
import { XRPCError } from '@externdefs/bluesky-client/xrpc';
22

33
import type { At } from '../atp-schema';
44
import { multiagent } from '../globals/agent';
@@ -459,7 +459,7 @@ export const finalizeRt = async (uid: At.DID, rt: PreliminaryRichText) => {
459459
features: [{ $type: 'app.bsky.richtext.facet#mention', did: did }],
460460
});
461461
} catch (err) {
462-
if (err instanceof XRPCError && err.error === 'InvalidRequest') {
462+
if (err instanceof XRPCError && err.kind === 'InvalidRequest') {
463463
throw new InvalidHandleError(handle);
464464
}
465465

app/api/utils/misc.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { XRPCError } from '@externdefs/bluesky-client/xrpc-utils';
1+
import { XRPCError } from '@externdefs/bluesky-client/xrpc';
22

33
import type { At } from '../atp-schema';
44
import { MultiagentError } from '../classes/multiagent';
@@ -53,7 +53,7 @@ export const followAbortSignal = (signals: (AbortSignal | undefined)[]) => {
5353
};
5454

5555
export const formatXRPCError = (err: XRPCError): string => {
56-
const name = err.error;
56+
const name = err.kind;
5757
return (name ? name + ': ' : '') + err.message;
5858
};
5959

@@ -72,7 +72,7 @@ export const formatQueryError = (err: unknown): string => {
7272
}
7373

7474
if (err instanceof XRPCError) {
75-
const error = err.error;
75+
const error = err.kind;
7676

7777
if (error === 'InvalidToken' || error === 'ExpiredToken') {
7878
return `Account session is no longer valid, please sign in again`;

app/desktop/components/panes/dialogs/ProfileSettingsPaneDialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createMemo, createSignal as signal } from 'solid-js';
22

3-
import { XRPCError } from '@externdefs/bluesky-client/xrpc-utils';
3+
import { XRPCError } from '@externdefs/bluesky-client/xrpc';
44
import { createMutation, useQueryClient } from '@pkg/solid-query';
55

66
import TextareaAutosize from 'solid-textarea-autosize';
@@ -96,7 +96,7 @@ const ProfileSettingsPaneDialog = (props: ProfileSettingsPaneDialogProps) => {
9696
} catch (err) {
9797
// If it's anything else than an InvalidRequest (not found), throw an error
9898

99-
if (!(err instanceof XRPCError) || err.error !== 'InvalidRequest') {
99+
if (!(err instanceof XRPCError) || err.kind !== 'InvalidRequest') {
100100
throw err;
101101
}
102102
}

0 commit comments

Comments
 (0)