@atproto/bsky 0.0.249 → 0.0.250

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/api/age-assurance/const.d.ts.map +1 -1
  3. package/dist/api/age-assurance/const.js +19 -0
  4. package/dist/api/age-assurance/const.js.map +1 -1
  5. package/dist/api/age-assurance/kws/age-verified.d.ts +20 -0
  6. package/dist/api/age-assurance/kws/age-verified.d.ts.map +1 -1
  7. package/dist/api/age-assurance/kws/age-verified.js +6 -0
  8. package/dist/api/age-assurance/kws/age-verified.js.map +1 -1
  9. package/dist/api/app/bsky/graph/muteActor.d.ts.map +1 -1
  10. package/dist/api/app/bsky/graph/muteActor.js +3 -0
  11. package/dist/api/app/bsky/graph/muteActor.js.map +1 -1
  12. package/dist/api/kws/types.d.ts +33 -0
  13. package/dist/api/kws/types.d.ts.map +1 -1
  14. package/dist/api/kws/types.js +3 -0
  15. package/dist/api/kws/types.js.map +1 -1
  16. package/dist/data-plane/index.d.ts +0 -1
  17. package/dist/data-plane/index.d.ts.map +1 -1
  18. package/dist/data-plane/index.js +0 -1
  19. package/dist/data-plane/index.js.map +1 -1
  20. package/dist/data-plane/server/bsync-subscription.d.ts +47 -0
  21. package/dist/data-plane/server/bsync-subscription.d.ts.map +1 -0
  22. package/dist/data-plane/server/bsync-subscription.js +461 -0
  23. package/dist/data-plane/server/bsync-subscription.js.map +1 -0
  24. package/dist/data-plane/server/index.d.ts +1 -0
  25. package/dist/data-plane/server/index.d.ts.map +1 -1
  26. package/dist/data-plane/server/index.js +1 -0
  27. package/dist/data-plane/server/index.js.map +1 -1
  28. package/dist/lexicons/app/bsky/ageassurance/defs.defs.d.ts +4 -0
  29. package/dist/lexicons/app/bsky/ageassurance/defs.defs.d.ts.map +1 -1
  30. package/dist/lexicons/app/bsky/ageassurance/defs.defs.js +3 -0
  31. package/dist/lexicons/app/bsky/ageassurance/defs.defs.js.map +1 -1
  32. package/dist/lexicons/chat/bsky/convo/defs.defs.js +1 -1
  33. package/dist/lexicons/chat/bsky/convo/defs.defs.js.map +1 -1
  34. package/dist/lexicons/chat/bsky/group/editGroup.defs.d.ts +4 -4
  35. package/dist/lexicons/chat/bsky/group/editGroup.defs.js +2 -2
  36. package/dist/lexicons/chat/bsky/group/editGroup.defs.js.map +1 -1
  37. package/dist/lexicons/chat/bsky/moderation/defs.defs.js +1 -1
  38. package/dist/lexicons/chat/bsky/moderation/defs.defs.js.map +1 -1
  39. package/package.json +9 -9
  40. package/src/api/age-assurance/const.ts +19 -0
  41. package/src/api/age-assurance/kws/age-verified.test.ts +98 -0
  42. package/src/api/age-assurance/kws/age-verified.ts +6 -0
  43. package/src/api/app/bsky/graph/muteActor.ts +3 -0
  44. package/src/api/kws/types.ts +11 -0
  45. package/src/api/kws/util.test.ts +50 -0
  46. package/src/data-plane/index.ts +0 -1
  47. package/src/data-plane/{bsync/index.ts → server/bsync-subscription.ts} +245 -121
  48. package/src/data-plane/server/index.ts +1 -0
  49. package/tests/data-plane/thread-mutes.test.ts +2 -0
  50. package/tests/stash.test.ts +6 -1
  51. package/tests/views/age-assurance-v2.test.ts +3 -0
  52. package/tests/views/age-assurance.test.ts +8 -0
  53. package/tests/views/bookmarks.test.ts +19 -0
  54. package/tests/views/drafts.test.ts +25 -2
  55. package/tests/views/mute-lists.test.ts +2 -0
  56. package/tests/views/mutes.test.ts +1 -0
  57. package/tests/views/notifications.test.ts +16 -0
  58. package/tsconfig.build.tsbuildinfo +1 -1
  59. package/dist/data-plane/bsync/index.d.ts +0 -11
  60. package/dist/data-plane/bsync/index.d.ts.map +0 -1
  61. package/dist/data-plane/bsync/index.js +0 -376
  62. package/dist/data-plane/bsync/index.js.map +0 -1
@@ -1,376 +0,0 @@
1
- import assert from 'node:assert';
2
- import events from 'node:events';
3
- import { expressConnectMiddleware } from '@connectrpc/connect-express';
4
- import express from 'express';
5
- // eslint-disable-next-line import/default
6
- import httpTerminator from 'http-terminator';
7
- import { TID } from '@atproto/common';
8
- import { lexParse } from '@atproto/lex';
9
- import { AtUri } from '@atproto/syntax';
10
- import { app } from '../../lexicons/index.js';
11
- import { httpLogger } from '../../logger.js';
12
- import { Service } from '../../proto/bsync_connect.js';
13
- import { Method, MuteOperation_Type, } from '../../proto/bsync_pb.js';
14
- import { Namespaces } from '../../stash.js';
15
- import { countAll, excluded } from '../server/db/util.js';
16
- export class MockBsync {
17
- constructor(server) {
18
- this.server = server;
19
- this.terminator = httpTerminator.createHttpTerminator({ server });
20
- }
21
- static async create(db, port) {
22
- const app = express();
23
- const routes = createRoutes(db);
24
- app.use(expressConnectMiddleware({ routes }));
25
- const server = app.listen(port);
26
- await events.once(server, 'listening');
27
- return new MockBsync(server);
28
- }
29
- async destroy() {
30
- await this.terminator.terminate();
31
- }
32
- async [Symbol.asyncDispose]() {
33
- await this.destroy();
34
- }
35
- }
36
- const createRoutes = (db) => (router) => router.service(Service, {
37
- async addMuteOperation(req) {
38
- const { type, actorDid, subject } = req;
39
- if (type === MuteOperation_Type.ADD) {
40
- if (subject.startsWith('did:')) {
41
- assert(actorDid !== subject, 'cannot mute yourself'); // @TODO pass message through in http error
42
- await db.db
43
- .insertInto('mute')
44
- .values({
45
- mutedByDid: actorDid,
46
- subjectDid: subject,
47
- createdAt: new Date().toISOString(),
48
- })
49
- .onConflict((oc) => oc.doNothing())
50
- .execute();
51
- }
52
- else {
53
- const uri = new AtUri(subject);
54
- if (uri.collection === app.bsky.graph.list.$type) {
55
- await db.db
56
- .insertInto('list_mute')
57
- .values({
58
- mutedByDid: actorDid,
59
- listUri: subject,
60
- createdAt: new Date().toISOString(),
61
- })
62
- .onConflict((oc) => oc.doNothing())
63
- .execute();
64
- }
65
- else {
66
- await db.db
67
- .insertInto('thread_mute')
68
- .values({
69
- mutedByDid: actorDid,
70
- rootUri: subject,
71
- createdAt: new Date().toISOString(),
72
- })
73
- .onConflict((oc) => oc.doNothing())
74
- .execute();
75
- }
76
- }
77
- }
78
- else if (type === MuteOperation_Type.REMOVE) {
79
- if (subject.startsWith('did:')) {
80
- await db.db
81
- .deleteFrom('mute')
82
- .where('mutedByDid', '=', actorDid)
83
- .where('subjectDid', '=', subject)
84
- .execute();
85
- }
86
- else {
87
- const uri = new AtUri(subject);
88
- if (uri.collection === app.bsky.graph.list.$type) {
89
- await db.db
90
- .deleteFrom('list_mute')
91
- .where('mutedByDid', '=', actorDid)
92
- .where('listUri', '=', subject)
93
- .execute();
94
- }
95
- else {
96
- await db.db
97
- .deleteFrom('thread_mute')
98
- .where('mutedByDid', '=', actorDid)
99
- .where('rootUri', '=', subject)
100
- .execute();
101
- }
102
- }
103
- }
104
- else if (type === MuteOperation_Type.CLEAR) {
105
- await db.db
106
- .deleteFrom('mute')
107
- .where('mutedByDid', '=', actorDid)
108
- .execute();
109
- await db.db
110
- .deleteFrom('list_mute')
111
- .where('mutedByDid', '=', actorDid)
112
- .execute();
113
- }
114
- return {};
115
- },
116
- async scanMuteOperations() {
117
- throw new Error('not implemented');
118
- },
119
- async addNotifOperation(req) {
120
- const { actorDid, priority } = req;
121
- if (priority !== undefined) {
122
- await db.db
123
- .insertInto('actor_state')
124
- .values({
125
- did: actorDid,
126
- priorityNotifs: priority,
127
- lastSeenNotifs: new Date().toISOString(),
128
- })
129
- .onConflict((oc) => oc.column('did').doUpdateSet({ priorityNotifs: priority }))
130
- .execute();
131
- }
132
- return {};
133
- },
134
- async scanNotifOperations() {
135
- throw new Error('not implemented');
136
- },
137
- async putOperation(req) {
138
- const { actorDid, namespace, key, method, payload } = req;
139
- assert(method === Method.CREATE ||
140
- method === Method.UPDATE ||
141
- method === Method.DELETE, `Unsupported method: ${method}`);
142
- const now = new Date().toISOString();
143
- // Index all items into private_data.
144
- await handleGenericOperation(db, req, now);
145
- // Maintain bespoke indexes for certain namespaces.
146
- try {
147
- if (namespace ===
148
- Namespaces.AppBskyNotificationDefsSubjectActivitySubscription.$type) {
149
- await handleSubjectActivitySubscriptionOperation(db, req, now);
150
- }
151
- else if (namespace === Namespaces.AppBskyUnspeccedDefsAgeAssuranceEvent.$type) {
152
- await handleAgeAssuranceEventOperation(db, req, now);
153
- }
154
- else if (namespace === Namespaces.AppBskyAgeassuranceDefsEvent.$type) {
155
- await handleAgeAssuranceV2EventOperation(db, req, now);
156
- }
157
- else if (namespace === Namespaces.AppBskyBookmarkDefsBookmark.$type) {
158
- await handleBookmarkOperation(db, req, now);
159
- }
160
- else if (namespace === Namespaces.AppBskyDraftDefsDraftWithId.$type) {
161
- await handleDraftOperation(db, req, now);
162
- }
163
- }
164
- catch (err) {
165
- httpLogger.warn({ err, namespace }, 'mock bsync put operation failed');
166
- }
167
- return {
168
- operation: {
169
- id: TID.nextStr(),
170
- actorDid,
171
- namespace,
172
- key,
173
- method,
174
- payload,
175
- },
176
- };
177
- },
178
- async scanOperations() {
179
- throw new Error('not implemented');
180
- },
181
- async ping() {
182
- return {};
183
- },
184
- });
185
- // upsert into or remove from private_data
186
- const handleGenericOperation = async (db, req, now) => {
187
- const { actorDid, namespace, key, method, payload } = req;
188
- if (method === Method.CREATE || method === Method.UPDATE) {
189
- await db.db
190
- .insertInto('private_data')
191
- .values({
192
- actorDid,
193
- namespace,
194
- key,
195
- payload: Buffer.from(payload).toString('utf8'),
196
- indexedAt: now,
197
- updatedAt: now,
198
- })
199
- .onConflict((oc) => oc.columns(['actorDid', 'namespace', 'key']).doUpdateSet({
200
- payload: excluded(db.db, 'payload'),
201
- updatedAt: excluded(db.db, 'updatedAt'),
202
- }))
203
- .execute();
204
- }
205
- else if (method === Method.DELETE) {
206
- await db.db
207
- .deleteFrom('private_data')
208
- .where('actorDid', '=', actorDid)
209
- .where('namespace', '=', namespace)
210
- .where('key', '=', key)
211
- .execute();
212
- }
213
- else {
214
- assert.fail(`unexpected method ${method}`);
215
- }
216
- };
217
- const handleSubjectActivitySubscriptionOperation = async (db, req, now) => {
218
- const { actorDid, key, method, payload } = req;
219
- if (method === Method.DELETE) {
220
- return db.db
221
- .deleteFrom('activity_subscription')
222
- .where('creator', '=', actorDid)
223
- .where('key', '=', key)
224
- .execute();
225
- }
226
- const json = Buffer.from(payload).toString('utf8');
227
- const parsed = lexParse(json);
228
- const { subject, activitySubscription: { post, reply }, } = parsed;
229
- if (method === Method.CREATE) {
230
- return db.db
231
- .insertInto('activity_subscription')
232
- .values({
233
- creator: actorDid,
234
- subjectDid: subject,
235
- key,
236
- indexedAt: now,
237
- post,
238
- reply,
239
- })
240
- .execute();
241
- }
242
- return db.db
243
- .updateTable('activity_subscription')
244
- .where('creator', '=', actorDid)
245
- .where('key', '=', key)
246
- .set({
247
- indexedAt: now,
248
- post,
249
- reply,
250
- })
251
- .execute();
252
- };
253
- const handleAgeAssuranceEventOperation = async (db, req, _now) => {
254
- const { actorDid, method, payload } = req;
255
- if (method !== Method.CREATE)
256
- return;
257
- const parsed = lexParse(Buffer.from(payload).toString('utf8'));
258
- const { status, createdAt } = parsed;
259
- const update = {
260
- ageAssuranceStatus: status,
261
- ageAssuranceLastInitiatedAt: status === 'pending' ? createdAt : undefined,
262
- };
263
- return db.db
264
- .updateTable('actor')
265
- .set(update)
266
- .where('did', '=', actorDid)
267
- .execute();
268
- };
269
- const handleAgeAssuranceV2EventOperation = async (db, req, _now) => {
270
- const { actorDid, method, payload } = req;
271
- if (method !== Method.CREATE)
272
- return;
273
- const parsed = lexParse(Buffer.from(payload).toString('utf8'));
274
- const { status, createdAt, access, countryCode, regionCode } = parsed;
275
- const update = {
276
- ageAssuranceStatus: status,
277
- ageAssuranceLastInitiatedAt: status === 'pending' ? createdAt : undefined,
278
- ageAssuranceAccess: access,
279
- ageAssuranceCountryCode: countryCode,
280
- ageAssuranceRegionCode: regionCode,
281
- };
282
- return db.db
283
- .updateTable('actor')
284
- .set(update)
285
- .where('did', '=', actorDid)
286
- .execute();
287
- };
288
- const handleBookmarkOperation = async (db, req, now) => {
289
- const { actorDid, key, method, payload } = req;
290
- const updateAgg = (uri, dbTxn) => {
291
- return dbTxn.db
292
- .insertInto('post_agg')
293
- .values({
294
- uri,
295
- bookmarkCount: dbTxn.db
296
- .selectFrom('bookmark')
297
- .where('bookmark.subjectUri', '=', uri)
298
- .select(countAll.as('count')),
299
- })
300
- .onConflict((oc) => oc
301
- .column('uri')
302
- .doUpdateSet({ bookmarkCount: excluded(dbTxn.db, 'bookmarkCount') }))
303
- .execute();
304
- };
305
- if (method === Method.CREATE) {
306
- const parsed = lexParse(Buffer.from(payload).toString('utf8'));
307
- const { subject: { uri, cid }, } = parsed;
308
- await db.transaction(async (dbTxn) => {
309
- await dbTxn.db
310
- .insertInto('bookmark')
311
- .values({
312
- creator: actorDid,
313
- key,
314
- indexedAt: now,
315
- subjectUri: uri,
316
- subjectCid: cid,
317
- })
318
- .execute();
319
- await updateAgg(uri, dbTxn);
320
- });
321
- }
322
- if (method === Method.DELETE) {
323
- await db.transaction(async (dbTxn) => {
324
- const bookmark = await dbTxn.db
325
- .selectFrom('bookmark')
326
- .selectAll()
327
- .where('creator', '=', actorDid)
328
- .where('key', '=', key)
329
- .executeTakeFirst();
330
- if (bookmark) {
331
- await dbTxn.db
332
- .deleteFrom('bookmark')
333
- .where('creator', '=', actorDid)
334
- .where('key', '=', key)
335
- .execute();
336
- await updateAgg(bookmark.subjectUri, dbTxn);
337
- }
338
- });
339
- }
340
- };
341
- const handleDraftOperation = async (db, req, now) => {
342
- const { actorDid, key, method, payload } = req;
343
- if (method === Method.CREATE) {
344
- const payloadString = Buffer.from(payload).toString('utf8');
345
- await db.db
346
- .insertInto('draft')
347
- .values({
348
- creator: actorDid,
349
- key,
350
- createdAt: now,
351
- updatedAt: now,
352
- payload: payloadString,
353
- })
354
- .execute();
355
- }
356
- if (method === Method.UPDATE) {
357
- const payloadString = Buffer.from(payload).toString('utf8');
358
- await db.db
359
- .updateTable('draft')
360
- .where('creator', '=', actorDid)
361
- .where('key', '=', key)
362
- .set({
363
- updatedAt: now,
364
- payload: payloadString,
365
- })
366
- .execute();
367
- }
368
- if (method === Method.DELETE) {
369
- await db.db
370
- .deleteFrom('draft')
371
- .where('creator', '=', actorDid)
372
- .where('key', '=', key)
373
- .execute();
374
- }
375
- };
376
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/data-plane/bsync/index.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'node:assert'\nimport events from 'node:events'\nimport http from 'node:http'\nimport { ConnectRouter } from '@connectrpc/connect'\nimport { expressConnectMiddleware } from '@connectrpc/connect-express'\nimport express from 'express'\n// eslint-disable-next-line import/default\nimport httpTerminator from 'http-terminator'\nimport { TID } from '@atproto/common'\nimport { lexParse } from '@atproto/lex'\nimport { AtUri } from '@atproto/syntax'\nimport { app } from '../../lexicons/index.js'\nimport { httpLogger } from '../../logger.js'\nimport { Service } from '../../proto/bsync_connect.js'\nimport {\n Method,\n MuteOperation_Type,\n PutOperationRequest,\n} from '../../proto/bsync_pb.js'\nimport { Namespaces } from '../../stash.js'\nimport { Database } from '../server/db/index.js'\nimport { countAll, excluded } from '../server/db/util.js'\n\nexport class MockBsync {\n private terminator: httpTerminator.HttpTerminator\n\n constructor(public server: http.Server) {\n this.terminator = httpTerminator.createHttpTerminator({ server })\n }\n\n static async create(db: Database, port: number) {\n const app = express()\n const routes = createRoutes(db)\n app.use(expressConnectMiddleware({ routes }))\n const server = app.listen(port)\n await events.once(server, 'listening')\n return new MockBsync(server)\n }\n\n async destroy() {\n await this.terminator.terminate()\n }\n\n async [Symbol.asyncDispose]() {\n await this.destroy()\n }\n}\n\nconst createRoutes = (db: Database) => (router: ConnectRouter) =>\n router.service(Service, {\n async addMuteOperation(req) {\n const { type, actorDid, subject } = req\n if (type === MuteOperation_Type.ADD) {\n if (subject.startsWith('did:')) {\n assert(actorDid !== subject, 'cannot mute yourself') // @TODO pass message through in http error\n await db.db\n .insertInto('mute')\n .values({\n mutedByDid: actorDid,\n subjectDid: subject,\n createdAt: new Date().toISOString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n } else {\n const uri = new AtUri(subject)\n if (uri.collection === app.bsky.graph.list.$type) {\n await db.db\n .insertInto('list_mute')\n .values({\n mutedByDid: actorDid,\n listUri: subject,\n createdAt: new Date().toISOString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n } else {\n await db.db\n .insertInto('thread_mute')\n .values({\n mutedByDid: actorDid,\n rootUri: subject,\n createdAt: new Date().toISOString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n }\n } else if (type === MuteOperation_Type.REMOVE) {\n if (subject.startsWith('did:')) {\n await db.db\n .deleteFrom('mute')\n .where('mutedByDid', '=', actorDid)\n .where('subjectDid', '=', subject)\n .execute()\n } else {\n const uri = new AtUri(subject)\n if (uri.collection === app.bsky.graph.list.$type) {\n await db.db\n .deleteFrom('list_mute')\n .where('mutedByDid', '=', actorDid)\n .where('listUri', '=', subject)\n .execute()\n } else {\n await db.db\n .deleteFrom('thread_mute')\n .where('mutedByDid', '=', actorDid)\n .where('rootUri', '=', subject)\n .execute()\n }\n }\n } else if (type === MuteOperation_Type.CLEAR) {\n await db.db\n .deleteFrom('mute')\n .where('mutedByDid', '=', actorDid)\n .execute()\n await db.db\n .deleteFrom('list_mute')\n .where('mutedByDid', '=', actorDid)\n .execute()\n }\n\n return {}\n },\n\n async scanMuteOperations() {\n throw new Error('not implemented')\n },\n\n async addNotifOperation(req) {\n const { actorDid, priority } = req\n if (priority !== undefined) {\n await db.db\n .insertInto('actor_state')\n .values({\n did: actorDid,\n priorityNotifs: priority,\n lastSeenNotifs: new Date().toISOString(),\n })\n .onConflict((oc) =>\n oc.column('did').doUpdateSet({ priorityNotifs: priority }),\n )\n .execute()\n }\n return {}\n },\n\n async scanNotifOperations() {\n throw new Error('not implemented')\n },\n\n async putOperation(req) {\n const { actorDid, namespace, key, method, payload } = req\n assert(\n method === Method.CREATE ||\n method === Method.UPDATE ||\n method === Method.DELETE,\n `Unsupported method: ${method}`,\n )\n\n const now = new Date().toISOString()\n\n // Index all items into private_data.\n await handleGenericOperation(db, req, now)\n\n // Maintain bespoke indexes for certain namespaces.\n try {\n if (\n namespace ===\n Namespaces.AppBskyNotificationDefsSubjectActivitySubscription.$type\n ) {\n await handleSubjectActivitySubscriptionOperation(db, req, now)\n } else if (\n namespace === Namespaces.AppBskyUnspeccedDefsAgeAssuranceEvent.$type\n ) {\n await handleAgeAssuranceEventOperation(db, req, now)\n } else if (\n namespace === Namespaces.AppBskyAgeassuranceDefsEvent.$type\n ) {\n await handleAgeAssuranceV2EventOperation(db, req, now)\n } else if (namespace === Namespaces.AppBskyBookmarkDefsBookmark.$type) {\n await handleBookmarkOperation(db, req, now)\n } else if (namespace === Namespaces.AppBskyDraftDefsDraftWithId.$type) {\n await handleDraftOperation(db, req, now)\n }\n } catch (err) {\n httpLogger.warn({ err, namespace }, 'mock bsync put operation failed')\n }\n\n return {\n operation: {\n id: TID.nextStr(),\n actorDid,\n namespace,\n key,\n method,\n payload,\n },\n }\n },\n\n async scanOperations() {\n throw new Error('not implemented')\n },\n\n async ping() {\n return {}\n },\n })\n\n// upsert into or remove from private_data\nconst handleGenericOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, namespace, key, method, payload } = req\n if (method === Method.CREATE || method === Method.UPDATE) {\n await db.db\n .insertInto('private_data')\n .values({\n actorDid,\n namespace,\n key,\n payload: Buffer.from(payload).toString('utf8'),\n indexedAt: now,\n updatedAt: now,\n })\n .onConflict((oc) =>\n oc.columns(['actorDid', 'namespace', 'key']).doUpdateSet({\n payload: excluded(db.db, 'payload'),\n updatedAt: excluded(db.db, 'updatedAt'),\n }),\n )\n .execute()\n } else if (method === Method.DELETE) {\n await db.db\n .deleteFrom('private_data')\n .where('actorDid', '=', actorDid)\n .where('namespace', '=', namespace)\n .where('key', '=', key)\n .execute()\n } else {\n assert.fail(`unexpected method ${method}`)\n }\n}\n\nconst handleSubjectActivitySubscriptionOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, key, method, payload } = req\n\n if (method === Method.DELETE) {\n return db.db\n .deleteFrom('activity_subscription')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .execute()\n }\n\n const json = Buffer.from(payload).toString('utf8')\n const parsed =\n lexParse<app.bsky.notification.defs.SubjectActivitySubscription>(json)\n const {\n subject,\n activitySubscription: { post, reply },\n } = parsed\n\n if (method === Method.CREATE) {\n return db.db\n .insertInto('activity_subscription')\n .values({\n creator: actorDid,\n subjectDid: subject,\n key,\n indexedAt: now,\n post,\n reply,\n })\n .execute()\n }\n\n return db.db\n .updateTable('activity_subscription')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .set({\n indexedAt: now,\n post,\n reply,\n })\n .execute()\n}\n\nconst handleAgeAssuranceEventOperation = async (\n db: Database,\n req: PutOperationRequest,\n _now: string,\n) => {\n const { actorDid, method, payload } = req\n if (method !== Method.CREATE) return\n\n const parsed = lexParse<app.bsky.unspecced.defs.AgeAssuranceEvent>(\n Buffer.from(payload).toString('utf8'),\n )\n\n const { status, createdAt } = parsed\n\n const update = {\n ageAssuranceStatus: status,\n ageAssuranceLastInitiatedAt: status === 'pending' ? createdAt : undefined,\n }\n\n return db.db\n .updateTable('actor')\n .set(update)\n .where('did', '=', actorDid)\n .execute()\n}\n\nconst handleAgeAssuranceV2EventOperation = async (\n db: Database,\n req: PutOperationRequest,\n _now: string,\n) => {\n const { actorDid, method, payload } = req\n if (method !== Method.CREATE) return\n\n const parsed = lexParse<app.bsky.ageassurance.defs.Event>(\n Buffer.from(payload).toString('utf8'),\n )\n\n const { status, createdAt, access, countryCode, regionCode } = parsed\n\n const update = {\n ageAssuranceStatus: status,\n ageAssuranceLastInitiatedAt: status === 'pending' ? createdAt : undefined,\n ageAssuranceAccess: access,\n ageAssuranceCountryCode: countryCode,\n ageAssuranceRegionCode: regionCode,\n }\n\n return db.db\n .updateTable('actor')\n .set(update)\n .where('did', '=', actorDid)\n .execute()\n}\n\nconst handleBookmarkOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, key, method, payload } = req\n\n const updateAgg = (uri: string, dbTxn: Database) => {\n return dbTxn.db\n .insertInto('post_agg')\n .values({\n uri,\n bookmarkCount: dbTxn.db\n .selectFrom('bookmark')\n .where('bookmark.subjectUri', '=', uri)\n .select(countAll.as('count')),\n })\n .onConflict((oc) =>\n oc\n .column('uri')\n .doUpdateSet({ bookmarkCount: excluded(dbTxn.db, 'bookmarkCount') }),\n )\n .execute()\n }\n\n if (method === Method.CREATE) {\n const parsed = lexParse<app.bsky.bookmark.defs.Bookmark>(\n Buffer.from(payload).toString('utf8'),\n )\n const {\n subject: { uri, cid },\n } = parsed\n\n await db.transaction(async (dbTxn) => {\n await dbTxn.db\n .insertInto('bookmark')\n .values({\n creator: actorDid,\n key,\n indexedAt: now,\n subjectUri: uri,\n subjectCid: cid,\n })\n .execute()\n\n await updateAgg(uri, dbTxn)\n })\n }\n\n if (method === Method.DELETE) {\n await db.transaction(async (dbTxn) => {\n const bookmark = await dbTxn.db\n .selectFrom('bookmark')\n .selectAll()\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .executeTakeFirst()\n\n if (bookmark) {\n await dbTxn.db\n .deleteFrom('bookmark')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .execute()\n\n await updateAgg(bookmark.subjectUri, dbTxn)\n }\n })\n }\n}\n\nconst handleDraftOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, key, method, payload } = req\n\n if (method === Method.CREATE) {\n const payloadString = Buffer.from(payload).toString('utf8')\n\n await db.db\n .insertInto('draft')\n .values({\n creator: actorDid,\n key,\n createdAt: now,\n updatedAt: now,\n payload: payloadString,\n })\n .execute()\n }\n\n if (method === Method.UPDATE) {\n const payloadString = Buffer.from(payload).toString('utf8')\n\n await db.db\n .updateTable('draft')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .set({\n updatedAt: now,\n payload: payloadString,\n })\n .execute()\n }\n\n if (method === Method.DELETE) {\n await db.db\n .deleteFrom('draft')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .execute()\n }\n}\n"]}