@atproto/bsync 0.0.24 → 0.0.26-next.0
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.
- package/CHANGELOG.md +27 -0
- package/bin/migration-create.ts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +7 -12
- package/dist/client.js.map +1 -1
- package/dist/config.js +16 -24
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +6 -6
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +8 -36
- package/dist/context.js.map +1 -1
- package/dist/db/index.d.ts +6 -4
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +26 -101
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations/20240108T220751294Z-init.js +4 -8
- package/dist/db/migrations/20240108T220751294Z-init.js.map +1 -1
- package/dist/db/migrations/20240717T224303472Z-notif-ops.js +4 -8
- package/dist/db/migrations/20240717T224303472Z-notif-ops.js.map +1 -1
- package/dist/db/migrations/20250527T022203400Z-add-operation.js +5 -9
- package/dist/db/migrations/20250527T022203400Z-add-operation.js.map +1 -1
- package/dist/db/migrations/20250603T163446567Z-alter-operation.js +2 -6
- package/dist/db/migrations/20250603T163446567Z-alter-operation.js.map +1 -1
- package/dist/db/migrations/index.d.ts +4 -4
- package/dist/db/migrations/index.d.ts.map +1 -1
- package/dist/db/migrations/index.js +4 -40
- package/dist/db/migrations/index.js.map +1 -1
- package/dist/db/migrations/provider.js +2 -11
- package/dist/db/migrations/provider.js.map +1 -1
- package/dist/db/schema/index.d.ts +5 -5
- package/dist/db/schema/index.d.ts.map +1 -1
- package/dist/db/schema/index.js +1 -2
- package/dist/db/schema/index.js.map +1 -1
- package/dist/db/schema/mute_item.js +1 -4
- package/dist/db/schema/mute_item.js.map +1 -1
- package/dist/db/schema/mute_op.d.ts +1 -1
- package/dist/db/schema/mute_op.d.ts.map +1 -1
- package/dist/db/schema/mute_op.js +2 -5
- package/dist/db/schema/mute_op.js.map +1 -1
- package/dist/db/schema/notif_item.js +1 -4
- package/dist/db/schema/notif_item.js.map +1 -1
- package/dist/db/schema/notif_op.js +2 -5
- package/dist/db/schema/notif_op.js.map +1 -1
- package/dist/db/schema/operation.d.ts +2 -2
- package/dist/db/schema/operation.d.ts.map +1 -1
- package/dist/db/schema/operation.js +2 -5
- package/dist/db/schema/operation.js.map +1 -1
- package/dist/db/types.d.ts +3 -1
- package/dist/db/types.d.ts.map +1 -1
- package/dist/db/types.js +1 -2
- package/dist/db/types.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -88
- package/dist/index.js.map +1 -1
- package/dist/logger.js +8 -11
- package/dist/logger.js.map +1 -1
- package/dist/proto/bsync_connect.d.ts +10 -1
- package/dist/proto/bsync_connect.d.ts.map +1 -1
- package/dist/proto/bsync_connect.js +33 -27
- package/dist/proto/bsync_connect.js.map +1 -1
- package/dist/proto/bsync_pb.d.ts +38 -0
- package/dist/proto/bsync_pb.d.ts.map +1 -1
- package/dist/proto/bsync_pb.js +260 -680
- package/dist/proto/bsync_pb.js.map +1 -1
- package/dist/routes/add-mute-operation.d.ts +2 -2
- package/dist/routes/add-mute-operation.d.ts.map +1 -1
- package/dist/routes/add-mute-operation.js +28 -30
- package/dist/routes/add-mute-operation.js.map +1 -1
- package/dist/routes/add-notif-operation.d.ts +2 -2
- package/dist/routes/add-notif-operation.d.ts.map +1 -1
- package/dist/routes/add-notif-operation.js +14 -16
- package/dist/routes/add-notif-operation.js.map +1 -1
- package/dist/routes/auth.d.ts +1 -1
- package/dist/routes/auth.d.ts.map +1 -1
- package/dist/routes/auth.js +4 -8
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/delete-operations.d.ts +6 -0
- package/dist/routes/delete-operations.d.ts.map +1 -0
- package/dist/routes/delete-operations.js +36 -0
- package/dist/routes/delete-operations.js.map +1 -0
- package/dist/routes/index.d.ts +1 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +19 -22
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/put-operation.d.ts +2 -2
- package/dist/routes/put-operation.d.ts.map +1 -1
- package/dist/routes/put-operation.js +24 -37
- package/dist/routes/put-operation.js.map +1 -1
- package/dist/routes/scan-mute-operations.d.ts +2 -2
- package/dist/routes/scan-mute-operations.d.ts.map +1 -1
- package/dist/routes/scan-mute-operations.js +13 -15
- package/dist/routes/scan-mute-operations.js.map +1 -1
- package/dist/routes/scan-notif-operations.d.ts +2 -2
- package/dist/routes/scan-notif-operations.d.ts.map +1 -1
- package/dist/routes/scan-notif-operations.js +13 -15
- package/dist/routes/scan-notif-operations.js.map +1 -1
- package/dist/routes/scan-operations.d.ts +2 -2
- package/dist/routes/scan-operations.d.ts.map +1 -1
- package/dist/routes/scan-operations.js +13 -15
- package/dist/routes/scan-operations.js.map +1 -1
- package/dist/routes/util.d.ts +1 -0
- package/dist/routes/util.d.ts.map +1 -1
- package/dist/routes/util.js +21 -17
- package/dist/routes/util.js.map +1 -1
- package/{jest.config.js → jest.config.cjs} +8 -1
- package/package.json +14 -9
- package/proto/bsync.proto +10 -0
- package/src/client.ts +1 -1
- package/src/context.ts +7 -7
- package/src/db/index.ts +12 -8
- package/src/db/migrations/index.ts +4 -4
- package/src/db/schema/index.ts +5 -5
- package/src/db/schema/mute_op.ts +1 -1
- package/src/db/schema/operation.ts +2 -2
- package/src/db/types.ts +3 -1
- package/src/index.ts +17 -13
- package/src/proto/bsync_connect.ts +10 -1
- package/src/proto/bsync_pb.ts +80 -0
- package/src/routes/add-mute-operation.ts +10 -7
- package/src/routes/add-notif-operation.ts +7 -7
- package/src/routes/auth.ts +1 -1
- package/src/routes/delete-operations.ts +45 -0
- package/src/routes/index.ts +10 -8
- package/src/routes/put-operation.ts +12 -24
- package/src/routes/scan-mute-operations.ts +6 -6
- package/src/routes/scan-notif-operations.ts +6 -6
- package/src/routes/scan-operations.ts +6 -6
- package/src/routes/util.ts +16 -0
- package/tests/delete-operations.test.ts +108 -0
- package/tests/mutes.test.ts +2 -2
- package/tests/notifications.test.ts +2 -2
- package/tests/operations.test.ts +2 -2
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.tests.json +1 -1
package/dist/routes/util.js
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const connect_1 = require("@connectrpc/connect");
|
|
5
|
-
const syntax_1 = require("@atproto/syntax");
|
|
6
|
-
const validCursor = (cursor) => {
|
|
1
|
+
import { Code, ConnectError } from '@connectrpc/connect';
|
|
2
|
+
import { InvalidDidError, ensureValidAtUri, ensureValidDid, ensureValidNsid, } from '@atproto/syntax';
|
|
3
|
+
export const validCursor = (cursor) => {
|
|
7
4
|
if (cursor === '')
|
|
8
5
|
return null;
|
|
9
6
|
const int = parseInt(cursor, 10);
|
|
10
7
|
if (isNaN(int) || int < 0) {
|
|
11
|
-
throw new
|
|
8
|
+
throw new ConnectError('invalid cursor', Code.InvalidArgument);
|
|
12
9
|
}
|
|
13
10
|
return int;
|
|
14
11
|
};
|
|
15
|
-
|
|
16
|
-
const combineSignals = (a, b) => {
|
|
12
|
+
export const combineSignals = (a, b) => {
|
|
17
13
|
const controller = new AbortController();
|
|
18
14
|
for (const signal of [a, b]) {
|
|
19
15
|
if (signal.aborted) {
|
|
@@ -27,28 +23,36 @@ const combineSignals = (a, b) => {
|
|
|
27
23
|
}
|
|
28
24
|
return controller.signal;
|
|
29
25
|
};
|
|
30
|
-
|
|
31
|
-
const isValidDid = (did) => {
|
|
26
|
+
export const isValidDid = (did) => {
|
|
32
27
|
try {
|
|
33
|
-
|
|
28
|
+
ensureValidDid(did);
|
|
34
29
|
return true;
|
|
35
30
|
}
|
|
36
31
|
catch (err) {
|
|
37
|
-
if (err instanceof
|
|
32
|
+
if (err instanceof InvalidDidError) {
|
|
38
33
|
return false;
|
|
39
34
|
}
|
|
40
35
|
throw err;
|
|
41
36
|
}
|
|
42
37
|
};
|
|
43
|
-
|
|
44
|
-
const isValidAtUri = (uri) => {
|
|
38
|
+
export const isValidAtUri = (uri) => {
|
|
45
39
|
try {
|
|
46
|
-
|
|
40
|
+
ensureValidAtUri(uri);
|
|
47
41
|
return true;
|
|
48
42
|
}
|
|
49
43
|
catch {
|
|
50
44
|
return false;
|
|
51
45
|
}
|
|
52
46
|
};
|
|
53
|
-
|
|
47
|
+
export const validateNamespace = (namespace) => {
|
|
48
|
+
const parts = namespace.split('#');
|
|
49
|
+
if (parts.length !== 1 && parts.length !== 2) {
|
|
50
|
+
throw new Error('namespace must be in the format "nsid[#fragment]"');
|
|
51
|
+
}
|
|
52
|
+
const [nsid, fragment] = parts;
|
|
53
|
+
ensureValidNsid(nsid);
|
|
54
|
+
if (fragment && !/^[a-zA-Z][a-zA-Z0-9]*$/.test(fragment)) {
|
|
55
|
+
throw new Error('namespace fragment must be a valid identifier');
|
|
56
|
+
}
|
|
57
|
+
};
|
|
54
58
|
//# sourceMappingURL=util.js.map
|
package/dist/routes/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/routes/util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/routes/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,GAChB,MAAM,iBAAiB,CAAA;AAExB,MAAM,CAAC,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,YAAY,CAAC,gBAAgB,EAAE,IAAI,CAAC,eAAe,CAAC,CAAA;IAChE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,MAAM,CAAC,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;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,EAAE;IACxC,IAAI,CAAC;QACH,cAAc,CAAC,GAAG,CAAC,CAAA;QACnB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;YACnC,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAE,EAAE;IAC1C,IAAI,CAAC;QACH,gBAAgB,CAAC,GAAG,CAAC,CAAA;QACrB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAQ,EAAE;IAC3D,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAElC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IAED,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAA;IAE9B,eAAe,CAAC,IAAI,CAAC,CAAA;IACrB,IAAI,QAAQ,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;AACH,CAAC,CAAA","sourcesContent":["import { Code, ConnectError } from '@connectrpc/connect'\nimport {\n InvalidDidError,\n ensureValidAtUri,\n ensureValidDid,\n ensureValidNsid,\n} from '@atproto/syntax'\n\nexport const validCursor = (cursor: string): number | null => {\n if (cursor === '') return null\n const int = parseInt(cursor, 10)\n if (isNaN(int) || int < 0) {\n throw new ConnectError('invalid cursor', Code.InvalidArgument)\n }\n return int\n}\n\nexport const combineSignals = (a: AbortSignal, b: AbortSignal) => {\n const controller = new AbortController()\n for (const signal of [a, b]) {\n if (signal.aborted) {\n controller.abort()\n return signal\n }\n signal.addEventListener('abort', () => controller.abort(signal.reason), {\n // @ts-ignore https://github.com/DefinitelyTyped/DefinitelyTyped/pull/68625\n signal: controller.signal,\n })\n }\n return controller.signal\n}\n\nexport const isValidDid = (did: string) => {\n try {\n ensureValidDid(did)\n return true\n } catch (err) {\n if (err instanceof InvalidDidError) {\n return false\n }\n throw err\n }\n}\n\nexport const isValidAtUri = (uri: string) => {\n try {\n ensureValidAtUri(uri)\n return true\n } catch {\n return false\n }\n}\n\nexport const validateNamespace = (namespace: string): void => {\n const parts = namespace.split('#')\n\n if (parts.length !== 1 && parts.length !== 2) {\n throw new Error('namespace must be in the format \"nsid[#fragment]\"')\n }\n\n const [nsid, fragment] = parts\n\n ensureValidNsid(nsid)\n if (fragment && !/^[a-zA-Z][a-zA-Z0-9]*$/.test(fragment)) {\n throw new Error('namespace fragment must be a valid identifier')\n }\n}\n"]}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
/** @type {import('jest').Config} */
|
|
2
2
|
module.exports = {
|
|
3
3
|
displayName: 'Bsync',
|
|
4
|
-
transform: {
|
|
4
|
+
transform: {
|
|
5
|
+
'^.+\\.(t|j)s$': [
|
|
6
|
+
'@swc/jest',
|
|
7
|
+
{ jsc: { transform: {} }, module: { type: 'es6' } },
|
|
8
|
+
],
|
|
9
|
+
},
|
|
10
|
+
extensionsToTreatAsEsm: ['.ts'],
|
|
11
|
+
transformIgnorePatterns: [],
|
|
5
12
|
setupFiles: ['<rootDir>/../../jest.setup.ts'],
|
|
6
13
|
moduleNameMapper: { '^(\\.\\.?\\/.+)\\.js$': ['$1.ts', '$1.js'] },
|
|
7
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/bsync",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.26-next.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Sychronizing service for app.bsky App View (Bluesky API)",
|
|
6
6
|
"keywords": [
|
|
@@ -13,10 +13,8 @@
|
|
|
13
13
|
"url": "https://github.com/bluesky-social/atproto",
|
|
14
14
|
"directory": "packages/bsync"
|
|
15
15
|
},
|
|
16
|
-
"main": "dist/index.js",
|
|
17
|
-
"types": "dist/index.d.ts",
|
|
18
16
|
"engines": {
|
|
19
|
-
"node": ">=
|
|
17
|
+
"node": ">=22"
|
|
20
18
|
},
|
|
21
19
|
"dependencies": {
|
|
22
20
|
"@bufbuild/protobuf": "^1.5.0",
|
|
@@ -27,8 +25,8 @@
|
|
|
27
25
|
"pg": "^8.10.0",
|
|
28
26
|
"pino-http": "^8.2.1",
|
|
29
27
|
"typed-emitter": "^2.1.0",
|
|
30
|
-
"@atproto/common": "^0.
|
|
31
|
-
"@atproto/syntax": "^0.
|
|
28
|
+
"@atproto/common": "^0.6.0-next.0",
|
|
29
|
+
"@atproto/syntax": "^0.6.0-next.0"
|
|
32
30
|
},
|
|
33
31
|
"devDependencies": {
|
|
34
32
|
"@bufbuild/buf": "^1.28.1",
|
|
@@ -36,14 +34,21 @@
|
|
|
36
34
|
"@connectrpc/protoc-gen-connect-es": "^1.1.4",
|
|
37
35
|
"@types/pg": "^8.6.6",
|
|
38
36
|
"get-port": "^5.1.1",
|
|
39
|
-
"jest": "^
|
|
37
|
+
"jest": "^30.0.0",
|
|
40
38
|
"ts-node": "^10.8.2",
|
|
41
|
-
"typescript": "^
|
|
39
|
+
"typescript": "^6.0.3"
|
|
40
|
+
},
|
|
41
|
+
"type": "module",
|
|
42
|
+
"exports": {
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./dist/index.d.ts",
|
|
45
|
+
"default": "./dist/index.js"
|
|
46
|
+
}
|
|
42
47
|
},
|
|
43
48
|
"scripts": {
|
|
44
49
|
"build": "tsc --build tsconfig.build.json",
|
|
45
50
|
"start": "node --enable-source-maps dist/bin.js",
|
|
46
|
-
"test": "../dev-infra/with-test-db.sh jest",
|
|
51
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules ../dev-infra/with-test-db.sh jest",
|
|
47
52
|
"test:log": "tail -50 test.log | pino-pretty",
|
|
48
53
|
"test:updateSnapshot": "jest --updateSnapshot",
|
|
49
54
|
"migration:create": "ts-node ./bin/migration-create.ts",
|
package/proto/bsync.proto
CHANGED
|
@@ -105,6 +105,15 @@ message ScanOperationsResponse {
|
|
|
105
105
|
string cursor = 2;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
message DeleteOperationsByActorAndNamespaceRequest {
|
|
109
|
+
string actor_did = 1;
|
|
110
|
+
string namespace = 2;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
message DeleteOperationsByActorAndNamespaceResponse {
|
|
114
|
+
int32 deleted_count = 1;
|
|
115
|
+
}
|
|
116
|
+
|
|
108
117
|
|
|
109
118
|
// Ping
|
|
110
119
|
message PingRequest {}
|
|
@@ -119,6 +128,7 @@ service Service {
|
|
|
119
128
|
rpc ScanNotifOperations(ScanNotifOperationsRequest) returns (ScanNotifOperationsResponse);
|
|
120
129
|
rpc PutOperation(PutOperationRequest) returns (PutOperationResponse);
|
|
121
130
|
rpc ScanOperations(ScanOperationsRequest) returns (ScanOperationsResponse);
|
|
131
|
+
rpc DeleteOperationsByActorAndNamespace(DeleteOperationsByActorAndNamespaceRequest) returns (DeleteOperationsByActorAndNamespaceResponse);
|
|
122
132
|
// Ping
|
|
123
133
|
rpc Ping(PingRequest) returns (PingResponse);
|
|
124
134
|
}
|
package/src/client.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
ConnectTransportOptions,
|
|
8
8
|
createConnectTransport,
|
|
9
9
|
} from '@connectrpc/connect-node'
|
|
10
|
-
import { Service } from './proto/bsync_connect'
|
|
10
|
+
import { Service } from './proto/bsync_connect.js'
|
|
11
11
|
|
|
12
12
|
export type BsyncClient = PromiseClient<typeof Service>
|
|
13
13
|
|
package/src/context.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { EventEmitter } from 'node:
|
|
2
|
-
import TypedEventEmitter from 'typed-emitter'
|
|
3
|
-
import { ServerConfig } from './config'
|
|
4
|
-
import { Database } from './db'
|
|
5
|
-
import { createMuteOpChannel } from './db/schema/mute_op'
|
|
6
|
-
import { createNotifOpChannel } from './db/schema/notif_op'
|
|
7
|
-
import { createOperationChannel } from './db/schema/operation'
|
|
1
|
+
import { EventEmitter } from 'node:events'
|
|
2
|
+
import type TypedEventEmitter from 'typed-emitter'
|
|
3
|
+
import { ServerConfig } from './config.js'
|
|
4
|
+
import { Database } from './db/index.js'
|
|
5
|
+
import { createMuteOpChannel } from './db/schema/mute_op.js'
|
|
6
|
+
import { createNotifOpChannel } from './db/schema/notif_op.js'
|
|
7
|
+
import { createOperationChannel } from './db/schema/operation.js'
|
|
8
8
|
|
|
9
9
|
export type AppContextOptions = {
|
|
10
10
|
db: Database
|
package/src/db/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from 'node:assert'
|
|
2
|
-
import { EventEmitter } from 'node:
|
|
2
|
+
import { EventEmitter } from 'node:events'
|
|
3
3
|
import {
|
|
4
4
|
Kysely,
|
|
5
5
|
KyselyPlugin,
|
|
@@ -11,13 +11,17 @@ import {
|
|
|
11
11
|
RootOperationNode,
|
|
12
12
|
UnknownRow,
|
|
13
13
|
} from 'kysely'
|
|
14
|
-
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import
|
|
20
|
-
import {
|
|
14
|
+
// eslint-disable-next-line import/default
|
|
15
|
+
import pg from 'pg'
|
|
16
|
+
// eslint-disable-next-line import/no-named-as-default-member
|
|
17
|
+
const { Pool: PgPool, types: pgTypes } = pg
|
|
18
|
+
type PgPool = InstanceType<typeof PgPool>
|
|
19
|
+
import type TypedEmitter from 'typed-emitter'
|
|
20
|
+
import { dbLogger } from '../logger.js'
|
|
21
|
+
import * as migrations from './migrations/index.js'
|
|
22
|
+
import { DbMigrationProvider } from './migrations/provider.js'
|
|
23
|
+
import { DatabaseSchema, DatabaseSchemaType } from './schema/index.js'
|
|
24
|
+
import { PgOptions } from './types.js'
|
|
21
25
|
|
|
22
26
|
export class Database {
|
|
23
27
|
pool: PgPool
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// It's important that every migration is exported from here with the proper name. We'd simplify
|
|
3
3
|
// this with kysely's FileMigrationProvider, but it doesn't play nicely with the build process.
|
|
4
4
|
|
|
5
|
-
export * as _20240108T220751294Z from './20240108T220751294Z-init'
|
|
6
|
-
export * as _20240717T224303472Z from './20240717T224303472Z-notif-ops'
|
|
7
|
-
export * as _20250527T022203400Z from './20250527T022203400Z-add-operation'
|
|
8
|
-
export * as _20250603T163446567Z from './20250603T163446567Z-alter-operation'
|
|
5
|
+
export * as _20240108T220751294Z from './20240108T220751294Z-init.js'
|
|
6
|
+
export * as _20240717T224303472Z from './20240717T224303472Z-notif-ops.js'
|
|
7
|
+
export * as _20250527T022203400Z from './20250527T022203400Z-add-operation.js'
|
|
8
|
+
export * as _20250603T163446567Z from './20250603T163446567Z-alter-operation.js'
|
package/src/db/schema/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Kysely } from 'kysely'
|
|
2
|
-
import * as muteItem from './mute_item'
|
|
3
|
-
import * as muteOp from './mute_op'
|
|
4
|
-
import * as notifItem from './notif_item'
|
|
5
|
-
import * as notifOp from './notif_op'
|
|
6
|
-
import * as op from './operation'
|
|
2
|
+
import * as muteItem from './mute_item.js'
|
|
3
|
+
import * as muteOp from './mute_op.js'
|
|
4
|
+
import * as notifItem from './notif_item.js'
|
|
5
|
+
import * as notifOp from './notif_op.js'
|
|
6
|
+
import * as op from './operation.js'
|
|
7
7
|
|
|
8
8
|
export type DatabaseSchemaType = muteItem.PartialDB &
|
|
9
9
|
muteOp.PartialDB &
|
package/src/db/schema/mute_op.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GeneratedAlways } from 'kysely'
|
|
2
|
-
import { Method } from '../../proto/bsync_pb'
|
|
2
|
+
import { Method } from '../../proto/bsync_pb.js'
|
|
3
3
|
|
|
4
4
|
export type OperationMethod = Method.CREATE | Method.UPDATE | Method.DELETE
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ export interface Operation {
|
|
|
9
9
|
namespace: string
|
|
10
10
|
key: string
|
|
11
11
|
method: OperationMethod
|
|
12
|
-
payload: Uint8Array
|
|
12
|
+
payload: Uint8Array<ArrayBuffer>
|
|
13
13
|
createdAt: GeneratedAlways<Date>
|
|
14
14
|
}
|
|
15
15
|
|
package/src/db/types.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { DynamicModule, RawBuilder, SelectQueryBuilder } from 'kysely'
|
|
2
|
-
|
|
2
|
+
// eslint-disable-next-line import/default
|
|
3
|
+
import pg from 'pg'
|
|
4
|
+
type PgPool = pg.Pool
|
|
3
5
|
|
|
4
6
|
export type DbRef = RawBuilder | ReturnType<DynamicModule['ref']>
|
|
5
7
|
|
package/src/index.ts
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import events from 'node:events'
|
|
2
2
|
import http from 'node:http'
|
|
3
3
|
import { connectNodeAdapter } from '@connectrpc/connect-node'
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
4
|
+
// eslint-disable-next-line import/default, import/no-named-as-default-member
|
|
5
|
+
import httpTerminator from 'http-terminator'
|
|
6
|
+
// eslint-disable-next-line import/no-named-as-default-member
|
|
7
|
+
const { createHttpTerminator } = httpTerminator
|
|
8
|
+
type HttpTerminator = ReturnType<typeof createHttpTerminator>
|
|
9
|
+
import { ServerConfig } from './config.js'
|
|
10
|
+
import { AppContext, AppContextOptions } from './context.js'
|
|
11
|
+
import { createMuteOpChannel } from './db/schema/mute_op.js'
|
|
12
|
+
import { createNotifOpChannel } from './db/schema/notif_op.js'
|
|
13
|
+
import { createOperationChannel } from './db/schema/operation.js'
|
|
14
|
+
import { dbLogger, loggerMiddleware } from './logger.js'
|
|
15
|
+
import routes from './routes/index.js'
|
|
12
16
|
|
|
13
|
-
export * from './config'
|
|
14
|
-
export * from './client'
|
|
15
|
-
export { Database } from './db'
|
|
16
|
-
export { AppContext } from './context'
|
|
17
|
-
export { httpLogger } from './logger'
|
|
17
|
+
export * from './config.js'
|
|
18
|
+
export * from './client.js'
|
|
19
|
+
export { Database } from './db/index.js'
|
|
20
|
+
export { AppContext } from './context.js'
|
|
21
|
+
export { httpLogger } from './logger.js'
|
|
18
22
|
|
|
19
23
|
export class BsyncService {
|
|
20
24
|
public ctx: AppContext
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/* eslint-disable */
|
|
4
4
|
// @ts-nocheck
|
|
5
5
|
|
|
6
|
-
import { AddMuteOperationRequest, AddMuteOperationResponse, AddNotifOperationRequest, AddNotifOperationResponse, PingRequest, PingResponse, PutOperationRequest, PutOperationResponse, ScanMuteOperationsRequest, ScanMuteOperationsResponse, ScanNotifOperationsRequest, ScanNotifOperationsResponse, ScanOperationsRequest, ScanOperationsResponse } from "./bsync_pb";
|
|
6
|
+
import { AddMuteOperationRequest, AddMuteOperationResponse, AddNotifOperationRequest, AddNotifOperationResponse, DeleteOperationsByActorAndNamespaceRequest, DeleteOperationsByActorAndNamespaceResponse, PingRequest, PingResponse, PutOperationRequest, PutOperationResponse, ScanMuteOperationsRequest, ScanMuteOperationsResponse, ScanNotifOperationsRequest, ScanNotifOperationsResponse, ScanOperationsRequest, ScanOperationsResponse } from "./bsync_pb.js";
|
|
7
7
|
import { MethodKind } from "@bufbuild/protobuf";
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -68,6 +68,15 @@ export const Service = {
|
|
|
68
68
|
O: ScanOperationsResponse,
|
|
69
69
|
kind: MethodKind.Unary,
|
|
70
70
|
},
|
|
71
|
+
/**
|
|
72
|
+
* @generated from rpc bsync.Service.DeleteOperationsByActorAndNamespace
|
|
73
|
+
*/
|
|
74
|
+
deleteOperationsByActorAndNamespace: {
|
|
75
|
+
name: "DeleteOperationsByActorAndNamespace",
|
|
76
|
+
I: DeleteOperationsByActorAndNamespaceRequest,
|
|
77
|
+
O: DeleteOperationsByActorAndNamespaceResponse,
|
|
78
|
+
kind: MethodKind.Unary,
|
|
79
|
+
},
|
|
71
80
|
/**
|
|
72
81
|
* Ping
|
|
73
82
|
*
|
package/src/proto/bsync_pb.ts
CHANGED
|
@@ -763,6 +763,86 @@ export class ScanOperationsResponse extends Message<ScanOperationsResponse> {
|
|
|
763
763
|
}
|
|
764
764
|
}
|
|
765
765
|
|
|
766
|
+
/**
|
|
767
|
+
* @generated from message bsync.DeleteOperationsByActorAndNamespaceRequest
|
|
768
|
+
*/
|
|
769
|
+
export class DeleteOperationsByActorAndNamespaceRequest extends Message<DeleteOperationsByActorAndNamespaceRequest> {
|
|
770
|
+
/**
|
|
771
|
+
* @generated from field: string actor_did = 1;
|
|
772
|
+
*/
|
|
773
|
+
actorDid = "";
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* @generated from field: string namespace = 2;
|
|
777
|
+
*/
|
|
778
|
+
namespace = "";
|
|
779
|
+
|
|
780
|
+
constructor(data?: PartialMessage<DeleteOperationsByActorAndNamespaceRequest>) {
|
|
781
|
+
super();
|
|
782
|
+
proto3.util.initPartial(data, this);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
static readonly runtime: typeof proto3 = proto3;
|
|
786
|
+
static readonly typeName = "bsync.DeleteOperationsByActorAndNamespaceRequest";
|
|
787
|
+
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
|
788
|
+
{ no: 1, name: "actor_did", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
|
789
|
+
{ no: 2, name: "namespace", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
|
790
|
+
]);
|
|
791
|
+
|
|
792
|
+
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteOperationsByActorAndNamespaceRequest {
|
|
793
|
+
return new DeleteOperationsByActorAndNamespaceRequest().fromBinary(bytes, options);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteOperationsByActorAndNamespaceRequest {
|
|
797
|
+
return new DeleteOperationsByActorAndNamespaceRequest().fromJson(jsonValue, options);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteOperationsByActorAndNamespaceRequest {
|
|
801
|
+
return new DeleteOperationsByActorAndNamespaceRequest().fromJsonString(jsonString, options);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
static equals(a: DeleteOperationsByActorAndNamespaceRequest | PlainMessage<DeleteOperationsByActorAndNamespaceRequest> | undefined, b: DeleteOperationsByActorAndNamespaceRequest | PlainMessage<DeleteOperationsByActorAndNamespaceRequest> | undefined): boolean {
|
|
805
|
+
return proto3.util.equals(DeleteOperationsByActorAndNamespaceRequest, a, b);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* @generated from message bsync.DeleteOperationsByActorAndNamespaceResponse
|
|
811
|
+
*/
|
|
812
|
+
export class DeleteOperationsByActorAndNamespaceResponse extends Message<DeleteOperationsByActorAndNamespaceResponse> {
|
|
813
|
+
/**
|
|
814
|
+
* @generated from field: int32 deleted_count = 1;
|
|
815
|
+
*/
|
|
816
|
+
deletedCount = 0;
|
|
817
|
+
|
|
818
|
+
constructor(data?: PartialMessage<DeleteOperationsByActorAndNamespaceResponse>) {
|
|
819
|
+
super();
|
|
820
|
+
proto3.util.initPartial(data, this);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
static readonly runtime: typeof proto3 = proto3;
|
|
824
|
+
static readonly typeName = "bsync.DeleteOperationsByActorAndNamespaceResponse";
|
|
825
|
+
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
|
826
|
+
{ no: 1, name: "deleted_count", kind: "scalar", T: 5 /* ScalarType.INT32 */ },
|
|
827
|
+
]);
|
|
828
|
+
|
|
829
|
+
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteOperationsByActorAndNamespaceResponse {
|
|
830
|
+
return new DeleteOperationsByActorAndNamespaceResponse().fromBinary(bytes, options);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteOperationsByActorAndNamespaceResponse {
|
|
834
|
+
return new DeleteOperationsByActorAndNamespaceResponse().fromJson(jsonValue, options);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteOperationsByActorAndNamespaceResponse {
|
|
838
|
+
return new DeleteOperationsByActorAndNamespaceResponse().fromJsonString(jsonString, options);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
static equals(a: DeleteOperationsByActorAndNamespaceResponse | PlainMessage<DeleteOperationsByActorAndNamespaceResponse> | undefined, b: DeleteOperationsByActorAndNamespaceResponse | PlainMessage<DeleteOperationsByActorAndNamespaceResponse> | undefined): boolean {
|
|
842
|
+
return proto3.util.equals(DeleteOperationsByActorAndNamespaceResponse, a, b);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
766
846
|
/**
|
|
767
847
|
* Ping
|
|
768
848
|
*
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { Code, ConnectError, ServiceImpl } from '@connectrpc/connect'
|
|
2
2
|
import { sql } from 'kysely'
|
|
3
3
|
import { AtUri } from '@atproto/syntax'
|
|
4
|
-
import { AppContext } from '../context'
|
|
5
|
-
import { Database } from '../db'
|
|
6
|
-
import { createMuteOpChannel } from '../db/schema/mute_op'
|
|
7
|
-
import { Service } from '../proto/bsync_connect'
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
import { AppContext } from '../context.js'
|
|
5
|
+
import { Database } from '../db/index.js'
|
|
6
|
+
import { createMuteOpChannel } from '../db/schema/mute_op.js'
|
|
7
|
+
import { Service } from '../proto/bsync_connect.js'
|
|
8
|
+
import {
|
|
9
|
+
AddMuteOperationResponse,
|
|
10
|
+
MuteOperation_Type,
|
|
11
|
+
} from '../proto/bsync_pb.js'
|
|
12
|
+
import { authWithApiKey } from './auth.js'
|
|
13
|
+
import { isValidAtUri, isValidDid } from './util.js'
|
|
11
14
|
|
|
12
15
|
export default (ctx: AppContext): Partial<ServiceImpl<typeof Service>> => ({
|
|
13
16
|
async addMuteOperation(req, handlerCtx) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Code, ConnectError, ServiceImpl } from '@connectrpc/connect'
|
|
2
2
|
import { sql } from 'kysely'
|
|
3
|
-
import { AppContext } from '../context'
|
|
4
|
-
import { Database } from '../db'
|
|
5
|
-
import { createNotifOpChannel } from '../db/schema/notif_op'
|
|
6
|
-
import { Service } from '../proto/bsync_connect'
|
|
7
|
-
import { AddNotifOperationResponse } from '../proto/bsync_pb'
|
|
8
|
-
import { authWithApiKey } from './auth'
|
|
9
|
-
import { isValidDid } from './util'
|
|
3
|
+
import { AppContext } from '../context.js'
|
|
4
|
+
import { Database } from '../db/index.js'
|
|
5
|
+
import { createNotifOpChannel } from '../db/schema/notif_op.js'
|
|
6
|
+
import { Service } from '../proto/bsync_connect.js'
|
|
7
|
+
import { AddNotifOperationResponse } from '../proto/bsync_pb.js'
|
|
8
|
+
import { authWithApiKey } from './auth.js'
|
|
9
|
+
import { isValidDid } from './util.js'
|
|
10
10
|
|
|
11
11
|
export default (ctx: AppContext): Partial<ServiceImpl<typeof Service>> => ({
|
|
12
12
|
async addNotifOperation(req, handlerCtx) {
|
package/src/routes/auth.ts
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Code, ConnectError, ServiceImpl } from '@connectrpc/connect'
|
|
2
|
+
import { AppContext } from '../context.js'
|
|
3
|
+
import { Service } from '../proto/bsync_connect.js'
|
|
4
|
+
import { DeleteOperationsByActorAndNamespaceResponse } from '../proto/bsync_pb.js'
|
|
5
|
+
import { authWithApiKey } from './auth.js'
|
|
6
|
+
import { isValidDid, validateNamespace } from './util.js'
|
|
7
|
+
|
|
8
|
+
export default (ctx: AppContext): Partial<ServiceImpl<typeof Service>> => ({
|
|
9
|
+
/**
|
|
10
|
+
* This method is responsible for deleting log rows from the bsync db, it has
|
|
11
|
+
* no other downstream effects. This method is called from the dataplane in
|
|
12
|
+
* response to a data deletion request initiated by a moderator in Ozone.
|
|
13
|
+
* It's the final step of the deletion process, basically cleaning up the
|
|
14
|
+
* breadcrumbs that resulted in the state we store in the dataplane.
|
|
15
|
+
*/
|
|
16
|
+
async deleteOperationsByActorAndNamespace(req, handlerCtx) {
|
|
17
|
+
authWithApiKey(ctx, handlerCtx)
|
|
18
|
+
const { db } = ctx
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
validateNamespace(req.namespace)
|
|
22
|
+
} catch (error) {
|
|
23
|
+
throw new ConnectError(
|
|
24
|
+
'requested namespace for deletion is invalid NSID',
|
|
25
|
+
Code.InvalidArgument,
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
if (!isValidDid(req.actorDid)) {
|
|
29
|
+
throw new ConnectError(
|
|
30
|
+
'requested actor_did for deletion is invalid DID',
|
|
31
|
+
Code.InvalidArgument,
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const deletedRows = await db.db
|
|
36
|
+
.deleteFrom('operation')
|
|
37
|
+
.where('actorDid', '=', req.actorDid)
|
|
38
|
+
.where('namespace', '=', req.namespace)
|
|
39
|
+
.returning('id')
|
|
40
|
+
.execute()
|
|
41
|
+
return new DeleteOperationsByActorAndNamespaceResponse({
|
|
42
|
+
deletedCount: deletedRows.length,
|
|
43
|
+
})
|
|
44
|
+
},
|
|
45
|
+
})
|
package/src/routes/index.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { ConnectRouter } from '@connectrpc/connect'
|
|
2
2
|
import { sql } from 'kysely'
|
|
3
|
-
import { AppContext } from '../context'
|
|
4
|
-
import { Service } from '../proto/bsync_connect'
|
|
5
|
-
import addMuteOperation from './add-mute-operation'
|
|
6
|
-
import addNotifOperation from './add-notif-operation'
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
3
|
+
import { AppContext } from '../context.js'
|
|
4
|
+
import { Service } from '../proto/bsync_connect.js'
|
|
5
|
+
import addMuteOperation from './add-mute-operation.js'
|
|
6
|
+
import addNotifOperation from './add-notif-operation.js'
|
|
7
|
+
import deleteOperations from './delete-operations.js'
|
|
8
|
+
import putOperation from './put-operation.js'
|
|
9
|
+
import scanMuteOperations from './scan-mute-operations.js'
|
|
10
|
+
import scanNotifOperations from './scan-notif-operations.js'
|
|
11
|
+
import scanOperations from './scan-operations.js'
|
|
11
12
|
|
|
12
13
|
export default (ctx: AppContext) => (router: ConnectRouter) => {
|
|
13
14
|
return router.service(Service, {
|
|
@@ -17,6 +18,7 @@ export default (ctx: AppContext) => (router: ConnectRouter) => {
|
|
|
17
18
|
...scanNotifOperations(ctx),
|
|
18
19
|
...putOperation(ctx),
|
|
19
20
|
...scanOperations(ctx),
|
|
21
|
+
...deleteOperations(ctx),
|
|
20
22
|
async ping() {
|
|
21
23
|
const { db } = ctx
|
|
22
24
|
await sql`select 1`.execute(db.db)
|