+1
-3
src/components/FollowingView.svelte
+1
-3
src/components/FollowingView.svelte
···
42
42
}
43
43
44
44
// schedule spinner to appear only if calculation takes > 200ms
45
-
calculationTimer = setTimeout(() => {
46
-
isLongCalculation = true;
47
-
}, 200);
45
+
calculationTimer = setTimeout(() => (isLongCalculation = true), 200);
48
46
// yield to main thread to allow UI to show spinner/update
49
47
await new Promise((resolve) => setTimeout(resolve, 0));
50
48
+3
-8
src/lib/cache.ts
+3
-8
src/lib/cache.ts
···
29
29
private writeFlushScheduled = false;
30
30
31
31
constructor() {
32
-
if (typeof indexedDB === 'undefined') {
33
-
return;
34
-
}
32
+
if (typeof indexedDB === 'undefined') return;
35
33
36
34
this.dbPromise = new Promise((resolve, reject) => {
37
35
const request = indexedDB.open(DB_NAME, DB_VERSION);
···
165
163
batch.forEach((op) => {
166
164
try {
167
165
let request: IDBRequest;
168
-
if (op.type === 'put') {
169
-
request = store.put(op.value, op.key);
170
-
} else {
171
-
request = store.delete(op.key);
172
-
}
166
+
if (op.type === 'put') request = store.put(op.value, op.key);
167
+
else request = store.delete(op.key);
173
168
174
169
request.onsuccess = () => op.resolve();
175
170
request.onerror = () => op.reject(request.error);
+65
-50
src/lib/state.svelte.ts
+65
-50
src/lib/state.svelte.ts
···
326
326
if (event.kind !== 'commit') return;
327
327
328
328
const { did, commit } = event;
329
-
if (commit.collection !== 'app.bsky.feed.post') return;
330
-
331
329
const uri: ResourceUri = `at://${did}/${commit.collection}/${commit.rkey}`;
332
-
333
-
if (commit.operation === 'create') {
334
-
const { cid, record } = commit;
335
-
const post: PostWithUri = {
336
-
uri,
337
-
cid,
338
-
// assume record is valid, we trust the jetstream
339
-
record: record as AppBskyFeedPost.Main
340
-
};
341
-
addPosts([[uri, post]]);
342
-
addTimeline(did, [uri]);
343
-
} else if (commit.operation === 'delete') {
344
-
allPosts.get(did)?.delete(uri);
330
+
if (commit.collection === 'app.bsky.feed.post') {
331
+
if (commit.operation === 'create') {
332
+
const { cid, record } = commit;
333
+
const post: PostWithUri = {
334
+
uri,
335
+
cid,
336
+
// assume record is valid, we trust the jetstream
337
+
record: record as AppBskyFeedPost.Main
338
+
};
339
+
addPosts([[uri, post]]);
340
+
addTimeline(did, [uri]);
341
+
} else if (commit.operation === 'delete') {
342
+
allPosts.get(did)?.delete(uri);
343
+
}
345
344
}
346
345
};
347
346
348
-
export const handleNotification = async (event: NotificationsStreamEvent) => {
349
-
if (event.type === 'message') {
350
-
const parsedSubjectUri = expect(parseCanonicalResourceUri(event.data.link.subject));
351
-
const did = parsedSubjectUri.repo as AtprotoDid;
352
-
const client = await getClient(did);
353
-
const subjectPost = await client.getRecord(
354
-
AppBskyFeedPost.mainSchema,
355
-
did,
356
-
parsedSubjectUri.rkey
357
-
);
358
-
if (!subjectPost.ok) return;
347
+
const handlePostNotification = async (event: NotificationsStreamEvent & { type: 'message' }) => {
348
+
const parsedSubjectUri = expect(parseCanonicalResourceUri(event.data.link.subject));
349
+
const did = parsedSubjectUri.repo as AtprotoDid;
350
+
const client = await getClient(did);
351
+
const subjectPost = await client.getRecord(
352
+
AppBskyFeedPost.mainSchema,
353
+
did,
354
+
parsedSubjectUri.rkey
355
+
);
356
+
if (!subjectPost.ok) return;
359
357
360
-
const parsedSourceUri = expect(parseCanonicalResourceUri(event.data.link.source_record));
361
-
const hydrated = await hydratePosts(client, did, [
362
-
{
363
-
record: subjectPost.value.record,
364
-
uri: event.data.link.subject,
365
-
cid: subjectPost.value.cid,
366
-
replies: {
367
-
cursor: null,
368
-
total: 1,
369
-
records: [
370
-
{
371
-
did: parsedSourceUri.repo,
372
-
collection: parsedSourceUri.collection,
373
-
rkey: parsedSourceUri.rkey
374
-
}
375
-
]
376
-
}
358
+
const parsedSourceUri = expect(parseCanonicalResourceUri(event.data.link.source_record));
359
+
const hydrated = await hydratePosts(client, did, [
360
+
{
361
+
record: subjectPost.value.record,
362
+
uri: event.data.link.subject,
363
+
cid: subjectPost.value.cid,
364
+
replies: {
365
+
cursor: null,
366
+
total: 1,
367
+
records: [
368
+
{
369
+
did: parsedSourceUri.repo,
370
+
collection: parsedSourceUri.collection,
371
+
rkey: parsedSourceUri.rkey
372
+
}
373
+
]
377
374
}
378
-
]);
379
-
if (!hydrated.ok) {
380
-
console.error(`cant hydrate posts ${did}: ${hydrated.error}`);
381
-
return;
375
+
}
376
+
]);
377
+
if (!hydrated.ok) {
378
+
console.error(`cant hydrate posts ${did}: ${hydrated.error}`);
379
+
return;
380
+
}
381
+
382
+
// console.log(hydrated);
383
+
addPosts(hydrated.value);
384
+
addTimeline(did, hydrated.value.keys());
385
+
};
386
+
387
+
const handleBacklink = (event: NotificationsStreamEvent & { type: 'message' }) => {
388
+
const parsedSource = expect(parseCanonicalResourceUri(event.data.link.source_record));
389
+
addBacklinks(event.data.link.subject, event.data.link.source, [
390
+
{
391
+
did: parsedSource.repo,
392
+
collection: parsedSource.collection,
393
+
rkey: parsedSource.rkey
382
394
}
395
+
]);
396
+
};
383
397
384
-
// console.log(hydrated);
385
-
addPosts(hydrated.value);
386
-
addTimeline(did, hydrated.value.keys());
398
+
export const handleNotification = async (event: NotificationsStreamEvent) => {
399
+
if (event.type === 'message') {
400
+
if (event.data.link.source.startsWith('app.bsky.feed.post')) handlePostNotification(event);
401
+
else handleBacklink(event);
387
402
}
388
403
};
389
404
+4
-2
src/routes/+page.svelte
+4
-2
src/routes/+page.svelte
···
114
114
newAccounts.map((account) => account.did),
115
115
'app.bsky.feed.post:reply.parent.uri',
116
116
'app.bsky.feed.post:embed.record.record.uri',
117
-
'app.bsky.feed.post:embed.record.uri'
117
+
'app.bsky.feed.post:embed.record.uri',
118
+
'app.bsky.feed.repost:subject.uri'
118
119
)
119
120
);
120
121
});
···
127
128
const jetstreamSub = new JetstreamSubscription({
128
129
url: $settings.endpoints.jetstream,
129
130
wantedCollections: ['app.bsky.feed.post'],
130
-
wantedDids: ['did:web:guestbook.gaze.systems'] // initially contain sentinel
131
+
// this is here because if wantedDids is zero jetstream will send all events
132
+
wantedDids: ['did:web:guestbook.gaze.systems']
131
133
});
132
134
jetstream.set(jetstreamSub);
133
135