@atproto/bsync 0.0.3 → 0.0.5

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 (80) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/buf.gen.yaml +2 -2
  3. package/dist/context.d.ts +2 -0
  4. package/dist/context.d.ts.map +1 -1
  5. package/dist/context.js +1 -0
  6. package/dist/context.js.map +1 -1
  7. package/dist/db/migrations/20240717T224303472Z-notif-ops.d.ts +4 -0
  8. package/dist/db/migrations/20240717T224303472Z-notif-ops.d.ts.map +1 -0
  9. package/dist/db/migrations/20240717T224303472Z-notif-ops.js +26 -0
  10. package/dist/db/migrations/20240717T224303472Z-notif-ops.js.map +1 -0
  11. package/dist/db/migrations/index.d.ts +1 -0
  12. package/dist/db/migrations/index.d.ts.map +1 -1
  13. package/dist/db/migrations/index.js +2 -1
  14. package/dist/db/migrations/index.js.map +1 -1
  15. package/dist/db/schema/index.d.ts +3 -1
  16. package/dist/db/schema/index.d.ts.map +1 -1
  17. package/dist/db/schema/notif_item.d.ts +12 -0
  18. package/dist/db/schema/notif_item.d.ts.map +1 -0
  19. package/dist/db/schema/notif_item.js +5 -0
  20. package/dist/db/schema/notif_item.js.map +1 -0
  21. package/dist/db/schema/notif_op.d.ts +14 -0
  22. package/dist/db/schema/notif_op.d.ts.map +1 -0
  23. package/dist/db/schema/notif_op.js +6 -0
  24. package/dist/db/schema/notif_op.js.map +1 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +8 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/logger.d.ts +4 -1
  29. package/dist/logger.d.ts.map +1 -1
  30. package/dist/logger.js +31 -8
  31. package/dist/logger.js.map +1 -1
  32. package/dist/proto/bsync_connect.d.ts +19 -1
  33. package/dist/proto/bsync_connect.d.ts.map +1 -1
  34. package/dist/proto/bsync_connect.js +19 -1
  35. package/dist/proto/bsync_connect.js.map +1 -1
  36. package/dist/proto/bsync_pb.d.ts +105 -0
  37. package/dist/proto/bsync_pb.d.ts.map +1 -1
  38. package/dist/proto/bsync_pb.js +325 -2
  39. package/dist/proto/bsync_pb.js.map +1 -1
  40. package/dist/routes/add-mute-operation.d.ts.map +1 -1
  41. package/dist/routes/add-mute-operation.js +7 -26
  42. package/dist/routes/add-mute-operation.js.map +1 -1
  43. package/dist/routes/add-notif-operation.d.ts +6 -0
  44. package/dist/routes/add-notif-operation.d.ts.map +1 -0
  45. package/dist/routes/add-notif-operation.js +63 -0
  46. package/dist/routes/add-notif-operation.js.map +1 -0
  47. package/dist/routes/index.d.ts.map +1 -1
  48. package/dist/routes/index.js +4 -0
  49. package/dist/routes/index.js.map +1 -1
  50. package/dist/routes/scan-mute-operations.d.ts.map +1 -1
  51. package/dist/routes/scan-mute-operations.js +3 -26
  52. package/dist/routes/scan-mute-operations.js.map +1 -1
  53. package/dist/routes/scan-notif-operations.d.ts +6 -0
  54. package/dist/routes/scan-notif-operations.d.ts.map +1 -0
  55. package/dist/routes/scan-notif-operations.js +56 -0
  56. package/dist/routes/scan-notif-operations.js.map +1 -0
  57. package/dist/routes/util.d.ts +6 -0
  58. package/dist/routes/util.d.ts.map +1 -0
  59. package/dist/routes/util.js +54 -0
  60. package/dist/routes/util.js.map +1 -0
  61. package/package.json +3 -2
  62. package/proto/bsync.proto +29 -0
  63. package/src/context.ts +2 -0
  64. package/src/db/migrations/20240717T224303472Z-notif-ops.ts +24 -0
  65. package/src/db/migrations/index.ts +1 -0
  66. package/src/db/schema/index.ts +6 -1
  67. package/src/db/schema/notif_item.ts +13 -0
  68. package/src/db/schema/notif_op.ts +16 -0
  69. package/src/index.ts +8 -2
  70. package/src/logger.ts +11 -7
  71. package/src/proto/bsync_connect.ts +23 -1
  72. package/src/proto/bsync_pb.ts +318 -1
  73. package/src/routes/add-mute-operation.ts +7 -29
  74. package/src/routes/add-notif-operation.ts +80 -0
  75. package/src/routes/index.ts +4 -0
  76. package/src/routes/scan-mute-operations.ts +2 -25
  77. package/src/routes/scan-notif-operations.ts +64 -0
  78. package/src/routes/util.ts +51 -0
  79. package/tests/mutes.test.ts +2 -0
  80. package/tests/notifications.test.ts +209 -0
@@ -0,0 +1,6 @@
1
+ import { ServiceImpl } from '@connectrpc/connect';
2
+ import { Service } from '../proto/bsync_connect';
3
+ import AppContext from '../context';
4
+ declare const _default: (ctx: AppContext) => Partial<ServiceImpl<typeof Service>>;
5
+ export default _default;
6
+ //# sourceMappingURL=scan-notif-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-notif-operations.d.ts","sourceRoot":"","sources":["../../src/routes/scan-notif-operations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAEhD,OAAO,UAAU,MAAM,YAAY,CAAA;8BAKd,UAAU,KAAG,QAAQ,YAAY,cAAc,CAAC,CAAC;AAAtE,wBAsDE"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_events_1 = require("node:events");
4
+ const bsync_pb_1 = require("../proto/bsync_pb");
5
+ const auth_1 = require("./auth");
6
+ const util_1 = require("./util");
7
+ const notif_op_1 = require("../db/schema/notif_op");
8
+ exports.default = (ctx) => ({
9
+ async scanNotifOperations(req, handlerCtx) {
10
+ (0, auth_1.authWithApiKey)(ctx, handlerCtx);
11
+ const { db, events } = ctx;
12
+ const limit = req.limit || 1000;
13
+ const cursor = (0, util_1.validCursor)(req.cursor);
14
+ const nextNotifOpPromise = (0, node_events_1.once)(events, notif_op_1.createNotifOpChannel, {
15
+ signal: (0, util_1.combineSignals)(ctx.shutdown, AbortSignal.timeout(ctx.cfg.service.longPollTimeoutMs)),
16
+ });
17
+ nextNotifOpPromise.catch(() => null); // ensure timeout is always handled
18
+ const nextNotifOpPageQb = db.db
19
+ .selectFrom('notif_op')
20
+ .selectAll()
21
+ .where('id', '>', cursor ?? -1)
22
+ .orderBy('id', 'asc')
23
+ .limit(limit);
24
+ let ops = await nextNotifOpPageQb.execute();
25
+ if (!ops.length) {
26
+ // if there were no ops on the page, wait for an event then try again.
27
+ try {
28
+ await nextNotifOpPromise;
29
+ }
30
+ catch (err) {
31
+ ctx.shutdown.throwIfAborted();
32
+ return new bsync_pb_1.ScanNotifOperationsResponse({
33
+ operations: [],
34
+ cursor: req.cursor,
35
+ });
36
+ }
37
+ ops = await nextNotifOpPageQb.execute();
38
+ if (!ops.length) {
39
+ return new bsync_pb_1.ScanNotifOperationsResponse({
40
+ operations: [],
41
+ cursor: req.cursor,
42
+ });
43
+ }
44
+ }
45
+ const lastOp = ops[ops.length - 1];
46
+ return new bsync_pb_1.ScanNotifOperationsResponse({
47
+ operations: ops.map((op) => ({
48
+ id: op.id.toString(),
49
+ actorDid: op.actorDid,
50
+ priority: op.priority ?? undefined,
51
+ })),
52
+ cursor: lastOp.id.toString(),
53
+ });
54
+ },
55
+ });
56
+ //# sourceMappingURL=scan-notif-operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-notif-operations.js","sourceRoot":"","sources":["../../src/routes/scan-notif-operations.ts"],"names":[],"mappings":";;AAAA,6CAAkC;AAGlC,gDAA+D;AAE/D,iCAAuC;AACvC,iCAAoD;AACpD,oDAA4D;AAE5D,kBAAe,CAAC,GAAe,EAAwC,EAAE,CAAC,CAAC;IACzE,KAAK,CAAC,mBAAmB,CAAC,GAAG,EAAE,UAAU;QACvC,IAAA,qBAAc,EAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QAC/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,GAAG,CAAA;QAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,IAAI,CAAA;QAC/B,MAAM,MAAM,GAAG,IAAA,kBAAW,EAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACtC,MAAM,kBAAkB,GAAG,IAAA,kBAAI,EAAC,MAAM,EAAE,+BAAoB,EAAE;YAC5D,MAAM,EAAE,IAAA,qBAAc,EACpB,GAAG,CAAC,QAAQ,EACZ,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CACvD;SACF,CAAC,CAAA;QACF,kBAAkB,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA,CAAC,mCAAmC;QAExE,MAAM,iBAAiB,GAAG,EAAE,CAAC,EAAE;aAC5B,UAAU,CAAC,UAAU,CAAC;aACtB,SAAS,EAAE;aACX,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC;aAC9B,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;aACpB,KAAK,CAAC,KAAK,CAAC,CAAA;QAEf,IAAI,GAAG,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,CAAA;QAE3C,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YAChB,sEAAsE;YACtE,IAAI,CAAC;gBACH,MAAM,kBAAkB,CAAA;YAC1B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAA;gBAC7B,OAAO,IAAI,sCAA2B,CAAC;oBACrC,UAAU,EAAE,EAAE;oBACd,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAA;YACJ,CAAC;YACD,GAAG,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,CAAA;YACvC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;gBAChB,OAAO,IAAI,sCAA2B,CAAC;oBACrC,UAAU,EAAE,EAAE;oBACd,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAElC,OAAO,IAAI,sCAA2B,CAAC;YACrC,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC3B,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE;gBACpB,QAAQ,EAAE,EAAE,CAAC,QAAQ;gBACrB,QAAQ,EAAE,EAAE,CAAC,QAAQ,IAAI,SAAS;aACnC,CAAC,CAAC;YACH,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE;SAC7B,CAAC,CAAA;IACJ,CAAC;CACF,CAAC,CAAA"}
@@ -0,0 +1,6 @@
1
+ /// <reference types="node" />
2
+ export declare const validCursor: (cursor: string) => number | null;
3
+ export declare const combineSignals: (a: AbortSignal, b: AbortSignal) => AbortSignal;
4
+ export declare const isValidDid: (did: string) => boolean;
5
+ export declare const isValidAtUri: (uri: string) => boolean;
6
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/routes/util.ts"],"names":[],"mappings":";AAOA,eAAO,MAAM,WAAW,WAAY,MAAM,KAAG,MAAM,GAAG,IAOrD,CAAA;AAED,eAAO,MAAM,cAAc,MAAO,WAAW,KAAK,WAAW,gBAa5D,CAAA;AAED,eAAO,MAAM,UAAU,QAAS,MAAM,YAUrC,CAAA;AAED,eAAO,MAAM,YAAY,QAAS,MAAM,YAOvC,CAAA"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isValidAtUri = exports.isValidDid = exports.combineSignals = exports.validCursor = void 0;
4
+ const connect_1 = require("@connectrpc/connect");
5
+ const syntax_1 = require("@atproto/syntax");
6
+ const validCursor = (cursor) => {
7
+ if (cursor === '')
8
+ return null;
9
+ const int = parseInt(cursor, 10);
10
+ if (isNaN(int) || int < 0) {
11
+ throw new connect_1.ConnectError('invalid cursor', connect_1.Code.InvalidArgument);
12
+ }
13
+ return int;
14
+ };
15
+ exports.validCursor = validCursor;
16
+ const combineSignals = (a, b) => {
17
+ const controller = new AbortController();
18
+ for (const signal of [a, b]) {
19
+ if (signal.aborted) {
20
+ controller.abort();
21
+ return signal;
22
+ }
23
+ signal.addEventListener('abort', () => controller.abort(signal.reason), {
24
+ // @ts-ignore https://github.com/DefinitelyTyped/DefinitelyTyped/pull/68625
25
+ signal: controller.signal,
26
+ });
27
+ }
28
+ return controller.signal;
29
+ };
30
+ exports.combineSignals = combineSignals;
31
+ const isValidDid = (did) => {
32
+ try {
33
+ (0, syntax_1.ensureValidDid)(did);
34
+ return true;
35
+ }
36
+ catch (err) {
37
+ if (err instanceof syntax_1.InvalidDidError) {
38
+ return false;
39
+ }
40
+ throw err;
41
+ }
42
+ };
43
+ exports.isValidDid = isValidDid;
44
+ const isValidAtUri = (uri) => {
45
+ try {
46
+ (0, syntax_1.ensureValidAtUri)(uri);
47
+ return true;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ };
53
+ exports.isValidAtUri = isValidAtUri;
54
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/routes/util.ts"],"names":[],"mappings":";;;AAAA,iDAAwD;AACxD,4CAIwB;AAEjB,MAAM,WAAW,GAAG,CAAC,MAAc,EAAiB,EAAE;IAC3D,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,IAAI,CAAA;IAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAChC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,sBAAY,CAAC,gBAAgB,EAAE,cAAI,CAAC,eAAe,CAAC,CAAA;IAChE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAPY,QAAA,WAAW,eAOvB;AAEM,MAAM,cAAc,GAAG,CAAC,CAAc,EAAE,CAAc,EAAE,EAAE;IAC/D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,KAAK,MAAM,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC5B,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,UAAU,CAAC,KAAK,EAAE,CAAA;YAClB,OAAO,MAAM,CAAA;QACf,CAAC;QACD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;YACtE,2EAA2E;YAC3E,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,UAAU,CAAC,MAAM,CAAA;AAC1B,CAAC,CAAA;AAbY,QAAA,cAAc,kBAa1B;AAEM,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,EAAE;IACxC,IAAI,CAAC;QACH,IAAA,uBAAc,EAAC,GAAG,CAAC,CAAA;QACnB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,wBAAe,EAAE,CAAC;YACnC,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC,CAAA;AAVY,QAAA,UAAU,cAUtB;AAEM,MAAM,YAAY,GAAG,CAAC,GAAW,EAAE,EAAE;IAC1C,IAAI,CAAC;QACH,IAAA,yBAAgB,EAAC,GAAG,CAAC,CAAA;QACrB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC,CAAA;AAPY,QAAA,YAAY,gBAOxB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/bsync",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "license": "MIT",
5
5
  "description": "Sychronizing service for app.bsky App View (Bluesky API)",
6
6
  "keywords": [
@@ -24,7 +24,7 @@
24
24
  "pg": "^8.10.0",
25
25
  "pino-http": "^8.2.1",
26
26
  "typed-emitter": "^2.1.0",
27
- "@atproto/common": "^0.4.0",
27
+ "@atproto/common": "^0.4.1",
28
28
  "@atproto/syntax": "^0.3.0"
29
29
  },
30
30
  "devDependencies": {
@@ -32,6 +32,7 @@
32
32
  "@bufbuild/protoc-gen-es": "^1.5.0",
33
33
  "@connectrpc/protoc-gen-connect-es": "^1.1.4",
34
34
  "@types/pg": "^8.6.6",
35
+ "get-port": "^5.1.1",
35
36
  "jest": "^28.1.2",
36
37
  "ts-node": "^10.8.2"
37
38
  },
package/proto/bsync.proto CHANGED
@@ -41,6 +41,33 @@ message ScanMuteOperationsResponse {
41
41
  string cursor = 2;
42
42
  }
43
43
 
44
+ message NotifOperation {
45
+ string id = 1;
46
+ string actor_did = 2;
47
+ optional bool priority = 3;
48
+ }
49
+
50
+ message AddNotifOperationRequest {
51
+ string actor_did = 1;
52
+ optional bool priority = 2;
53
+ }
54
+
55
+ message AddNotifOperationResponse {
56
+ NotifOperation operation = 1;
57
+ }
58
+
59
+ message ScanNotifOperationsRequest {
60
+ string cursor = 1;
61
+ int32 limit = 2;
62
+ }
63
+
64
+ message ScanNotifOperationsResponse {
65
+ repeated NotifOperation operations = 1;
66
+ string cursor = 2;
67
+ }
68
+
69
+
70
+
44
71
  // Ping
45
72
  message PingRequest {}
46
73
  message PingResponse {}
@@ -50,6 +77,8 @@ service Service {
50
77
  // Sync
51
78
  rpc AddMuteOperation(AddMuteOperationRequest) returns (AddMuteOperationResponse);
52
79
  rpc ScanMuteOperations(ScanMuteOperationsRequest) returns (ScanMuteOperationsResponse);
80
+ rpc AddNotifOperation(AddNotifOperationRequest) returns (AddNotifOperationResponse);
81
+ rpc ScanNotifOperations(ScanNotifOperationsRequest) returns (ScanNotifOperationsResponse);
53
82
  // Ping
54
83
  rpc Ping(PingRequest) returns (PingResponse);
55
84
  }
package/src/context.ts CHANGED
@@ -2,6 +2,7 @@ import TypedEventEmitter from 'typed-emitter'
2
2
  import { ServerConfig } from './config'
3
3
  import Database from './db'
4
4
  import { createMuteOpChannel } from './db/schema/mute_op'
5
+ import { createNotifOpChannel } from './db/schema/notif_op'
5
6
  import { EventEmitter } from 'stream'
6
7
 
7
8
  export type AppContextOptions = {
@@ -43,4 +44,5 @@ export default AppContext
43
44
 
44
45
  export type AppEvents = {
45
46
  [createMuteOpChannel]: () => void
47
+ [createNotifOpChannel]: () => void
46
48
  }
@@ -0,0 +1,24 @@
1
+ import { Kysely, sql } from 'kysely'
2
+
3
+ export async function up(db: Kysely<unknown>): Promise<void> {
4
+ await db.schema
5
+ .createTable('notif_op')
6
+ .addColumn('id', 'bigserial', (col) => col.primaryKey())
7
+ .addColumn('actorDid', 'varchar', (col) => col.notNull())
8
+ .addColumn('priority', 'boolean')
9
+ .addColumn('createdAt', 'timestamptz', (col) =>
10
+ col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`),
11
+ )
12
+ .execute()
13
+ await db.schema
14
+ .createTable('notif_item')
15
+ .addColumn('actorDid', 'varchar', (col) => col.primaryKey())
16
+ .addColumn('priority', 'boolean', (col) => col.notNull())
17
+ .addColumn('fromId', 'bigint', (col) => col.notNull())
18
+ .execute()
19
+ }
20
+
21
+ export async function down(db: Kysely<unknown>): Promise<void> {
22
+ await db.schema.dropTable('notif_item').execute()
23
+ await db.schema.dropTable('notif_op').execute()
24
+ }
@@ -3,3 +3,4 @@
3
3
  // this with kysely's FileMigrationProvider, but it doesn't play nicely with the build process.
4
4
 
5
5
  export * as _20240108T220751294Z from './20240108T220751294Z-init'
6
+ export * as _20240717T224303472Z from './20240717T224303472Z-notif-ops'
@@ -1,8 +1,13 @@
1
1
  import { Kysely } from 'kysely'
2
2
  import * as muteOp from './mute_op'
3
3
  import * as muteItem from './mute_item'
4
+ import * as notifOp from './notif_op'
5
+ import * as notifItem from './notif_item'
4
6
 
5
- export type DatabaseSchemaType = muteItem.PartialDB & muteOp.PartialDB
7
+ export type DatabaseSchemaType = muteItem.PartialDB &
8
+ muteOp.PartialDB &
9
+ notifItem.PartialDB &
10
+ notifOp.PartialDB
6
11
 
7
12
  export type DatabaseSchema = Kysely<DatabaseSchemaType>
8
13
 
@@ -0,0 +1,13 @@
1
+ import { Selectable } from 'kysely'
2
+
3
+ export interface NotifItem {
4
+ actorDid: string
5
+ priority: boolean
6
+ fromId: number
7
+ }
8
+
9
+ export type NotifItemEntry = Selectable<NotifItem>
10
+
11
+ export const tableName = 'notif_item'
12
+
13
+ export type PartialDB = { [tableName]: NotifItem }
@@ -0,0 +1,16 @@
1
+ import { GeneratedAlways, Selectable } from 'kysely'
2
+
3
+ export interface NotifOp {
4
+ id: GeneratedAlways<number>
5
+ actorDid: string
6
+ priority: boolean | null
7
+ createdAt: GeneratedAlways<Date>
8
+ }
9
+
10
+ export type NotifOpEntry = Selectable<NotifOp>
11
+
12
+ export const tableName = 'notif_op'
13
+
14
+ export type PartialDB = { [tableName]: NotifOp }
15
+
16
+ export const createNotifOpChannel = 'notif_op_create' // used with listen/notify
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ import AppContext, { AppContextOptions } from './context'
7
7
  import { ServerConfig } from './config'
8
8
  import routes from './routes'
9
9
  import { createMuteOpChannel } from './db/schema/mute_op'
10
+ import { createNotifOpChannel } from './db/schema/notif_op'
10
11
 
11
12
  export * from './config'
12
13
  export * from './client'
@@ -88,10 +89,15 @@ export class BsyncService {
88
89
  this.ac.signal.addEventListener('abort', () => conn.release(), {
89
90
  once: true,
90
91
  })
91
- conn.query(`listen ${createMuteOpChannel}`) // if this errors, unhandled rejection should cause process to exit
92
+ // if these error, unhandled rejection should cause process to exit
93
+ conn.query(`listen ${createMuteOpChannel}`)
94
+ conn.query(`listen ${createNotifOpChannel}`)
92
95
  conn.on('notification', (notif) => {
93
96
  if (notif.channel === createMuteOpChannel) {
94
- this.ctx.events.emit('mute_op_create')
97
+ this.ctx.events.emit(createMuteOpChannel)
98
+ }
99
+ if (notif.channel === createNotifOpChannel) {
100
+ this.ctx.events.emit(createNotifOpChannel)
95
101
  }
96
102
  })
97
103
  }
package/src/logger.ts CHANGED
@@ -1,5 +1,6 @@
1
- import pinoHttp from 'pino-http'
2
- import { subsystemLogger } from '@atproto/common'
1
+ import { type IncomingMessage } from 'node:http'
2
+ import pinoHttp, { stdSerializers } from 'pino-http'
3
+ import { obfuscateHeaders, subsystemLogger } from '@atproto/common'
3
4
 
4
5
  export const dbLogger: ReturnType<typeof subsystemLogger> =
5
6
  subsystemLogger('bsync:db')
@@ -12,11 +13,14 @@ export const loggerMiddleware = pinoHttp({
12
13
  paths: ['req.headers.authorization'],
13
14
  },
14
15
  serializers: {
15
- err: (err) => {
16
- return {
17
- code: err?.code,
18
- message: err?.message,
19
- }
16
+ err: (err: unknown) => ({
17
+ code: err?.['code'],
18
+ message: err?.['message'],
19
+ }),
20
+ req: (req: IncomingMessage) => {
21
+ const serialized = stdSerializers.req(req)
22
+ const headers = obfuscateHeaders(serialized.headers)
23
+ return { ...serialized, headers }
20
24
  },
21
25
  },
22
26
  })
@@ -1,4 +1,4 @@
1
- // @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts,import_extension=.ts"
1
+ // @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts,import_extension="
2
2
  // @generated from file bsync.proto (package bsync, syntax proto3)
3
3
  /* eslint-disable */
4
4
  // @ts-nocheck
@@ -6,10 +6,14 @@
6
6
  import {
7
7
  AddMuteOperationRequest,
8
8
  AddMuteOperationResponse,
9
+ AddNotifOperationRequest,
10
+ AddNotifOperationResponse,
9
11
  PingRequest,
10
12
  PingResponse,
11
13
  ScanMuteOperationsRequest,
12
14
  ScanMuteOperationsResponse,
15
+ ScanNotifOperationsRequest,
16
+ ScanNotifOperationsResponse,
13
17
  } from './bsync_pb'
14
18
  import { MethodKind } from '@bufbuild/protobuf'
15
19
 
@@ -39,6 +43,24 @@ export const Service = {
39
43
  O: ScanMuteOperationsResponse,
40
44
  kind: MethodKind.Unary,
41
45
  },
46
+ /**
47
+ * @generated from rpc bsync.Service.AddNotifOperation
48
+ */
49
+ addNotifOperation: {
50
+ name: 'AddNotifOperation',
51
+ I: AddNotifOperationRequest,
52
+ O: AddNotifOperationResponse,
53
+ kind: MethodKind.Unary,
54
+ },
55
+ /**
56
+ * @generated from rpc bsync.Service.ScanNotifOperations
57
+ */
58
+ scanNotifOperations: {
59
+ name: 'ScanNotifOperations',
60
+ I: ScanNotifOperationsRequest,
61
+ O: ScanNotifOperationsResponse,
62
+ kind: MethodKind.Unary,
63
+ },
42
64
  /**
43
65
  * Ping
44
66
  *