+1
-1
eslint.config.mjs
+1
-1
eslint.config.mjs
···
1
1
import eslint from "@eslint/js";
2
2
import stylistic from "@stylistic/eslint-plugin";
3
-
import { defineConfig } from "eslint/config";
4
3
import prettier from "eslint-config-prettier";
5
4
import importPlugin from "eslint-plugin-import";
5
+
import { defineConfig } from "eslint/config";
6
6
import tseslint from "typescript-eslint";
7
7
8
8
export default defineConfig(
+2
rules/constants.ts
+2
rules/constants.ts
-5
rules/posts.ts
-5
rules/posts.ts
+2
-2
src/config.ts
+2
-2
src/config.ts
···
20
20
export const CURSOR_UPDATE_INTERVAL = process.env.CURSOR_UPDATE_INTERVAL
21
21
? Number(process.env.CURSOR_UPDATE_INTERVAL)
22
22
: 60000;
23
-
export const {LABEL_LIMIT} = process.env;
24
-
export const {LABEL_LIMIT_WAIT} = process.env;
23
+
export const { LABEL_LIMIT } = process.env;
24
+
export const { LABEL_LIMIT_WAIT } = process.env;
25
25
export const REDIS_URL = process.env.REDIS_URL ?? "redis://redis:6379";
+21
-18
src/main.ts
+21
-18
src/main.ts
···
2
2
import type {
3
3
CommitCreateEvent,
4
4
CommitUpdateEvent,
5
-
IdentityEvent} from "@skyware/jetstream";
6
-
import {
7
-
Jetstream,
5
+
IdentityEvent,
8
6
} from "@skyware/jetstream";
7
+
import { Jetstream } from "@skyware/jetstream";
9
8
import {
10
9
CURSOR_UPDATE_INTERVAL,
11
10
FIREHOSE_URL,
···
112
111
"app.bsky.feed.post",
113
112
(event: CommitCreateEvent<"app.bsky.feed.post">) => {
114
113
const atURI = `at://${event.did}/app.bsky.feed.post/${event.commit.rkey}`;
115
-
const hasEmbed = Object.prototype.hasOwnProperty.call(event.commit.record, "embed");
116
-
const hasFacets = Object.prototype.hasOwnProperty.call(event.commit.record, "facets");
117
-
const hasText = Object.prototype.hasOwnProperty.call(event.commit.record, "text");
114
+
const hasEmbed = Object.prototype.hasOwnProperty.call(
115
+
event.commit.record,
116
+
"embed",
117
+
);
118
+
const hasFacets = Object.prototype.hasOwnProperty.call(
119
+
event.commit.record,
120
+
"facets",
121
+
);
122
+
const hasText = Object.prototype.hasOwnProperty.call(
123
+
event.commit.record,
124
+
"text",
125
+
);
118
126
119
127
const tasks: Promise<void>[] = [];
120
128
···
136
144
137
145
// Check account age for quote posts
138
146
if (hasEmbed) {
139
-
const {embed} = event.commit.record;
147
+
const { embed } = event.commit.record;
140
148
if (
141
149
embed &&
142
150
typeof embed === "object" &&
···
170
178
if (hasFacets) {
171
179
// Check for facet spam (hidden mentions with duplicate byte positions)
172
180
const facets = event.commit.record.facets ?? null;
173
-
tasks.push(
174
-
checkFacetSpam(
175
-
event.did,
176
-
event.time_us,
177
-
atURI,
178
-
facets,
179
-
),
180
-
);
181
+
tasks.push(checkFacetSpam(event.did, event.time_us, atURI, facets));
181
182
182
183
const hasLinkType = facets?.some((facet) =>
183
184
facet.features.some(
···
225
226
}
226
227
227
228
if (hasEmbed) {
228
-
const {embed} = event.commit.record;
229
+
const { embed } = event.commit.record;
229
230
if (
230
231
embed &&
231
232
typeof embed === "object" &&
232
233
"$type" in embed &&
233
234
embed.$type === "app.bsky.embed.external"
234
235
) {
235
-
const {external} = embed as { external: { uri: string } };
236
+
const { external } = embed as { external: { uri: string } };
236
237
const posts: Post[] = [
237
238
{
238
239
did: event.did,
···
252
253
"$type" in embed &&
253
254
embed.$type === "app.bsky.embed.recordWithMedia"
254
255
) {
255
-
const {media} = embed as { media: { $type: string; external?: { uri: string } } };
256
+
const { media } = embed as {
257
+
media: { $type: string; external?: { uri: string } };
258
+
};
256
259
if (media.$type === "app.bsky.embed.external" && media.external) {
257
260
const posts: Post[] = [
258
261
{
-3
src/rules/account/tests/countStarterPacks.test.ts
-3
src/rules/account/tests/countStarterPacks.test.ts
+5
-1
src/rules/facets/facets.ts
+5
-1
src/rules/facets/facets.ts
···
52
52
positionMap.set(key, new Set());
53
53
}
54
54
const dids = positionMap.get(key);
55
-
if (dids && "did" in mentionFeature && typeof mentionFeature.did === "string") {
55
+
if (
56
+
dids &&
57
+
"did" in mentionFeature &&
58
+
typeof mentionFeature.did === "string"
59
+
) {
56
60
dids.add(mentionFeature.did);
57
61
}
58
62
}
-1
src/rules/facets/tests/facets.test.ts
-1
src/rules/facets/tests/facets.test.ts
+1
-8
src/rules/handles/checkHandles.test.ts
+1
-8
src/rules/handles/checkHandles.test.ts
···
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
1
import { beforeEach, describe, expect, it, vi } from "vitest";
9
2
import {
10
3
createAccountComment,
···
277
270
});
278
271
279
272
it("should handle very long handles", async () => {
280
-
const longHandle = `spam-${ "a".repeat(1000)}`;
273
+
const longHandle = `spam-${"a".repeat(1000)}`;
281
274
const time = Date.now();
282
275
await checkHandle("did:plc:user1", longHandle, time);
283
276
+4
-1
src/rules/handles/checkHandles.ts
+4
-1
src/rules/handles/checkHandles.ts
···
58
58
{ process: "CHECKHANDLE", did, handle, time, label: checkList.label },
59
59
"Reporting account",
60
60
);
61
-
void createAccountReport(did, `${time.toString()}: ${checkList.comment} - ${handle}`);
61
+
void createAccountReport(
62
+
did,
63
+
`${time.toString()}: ${checkList.comment} - ${handle}`,
64
+
);
62
65
}
63
66
64
67
if (checkList.commentAcct) {
-6
src/rules/posts/tests/checkPosts.test.ts
-6
src/rules/posts/tests/checkPosts.test.ts
-6
src/rules/profiles/tests/checkProfiles.test.ts
-6
src/rules/profiles/tests/checkProfiles.test.ts
-1
src/tests/accountThreshold.test.ts
-1
src/tests/accountThreshold.test.ts
-1
src/tests/agent.test.ts
-1
src/tests/agent.test.ts
-5
src/tests/moderation.test.ts
-5
src/tests/moderation.test.ts
-1
src/tests/redis.test.ts
-1
src/tests/redis.test.ts
+6
-6
src/tests/session.test.ts
+6
-6
src/tests/session.test.ts
···
1
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
1
import {
2
+
chmodSync,
3
3
existsSync,
4
4
mkdirSync,
5
-
rmSync,
6
-
writeFileSync,
7
5
readFileSync,
6
+
rmSync,
8
7
unlinkSync,
9
-
chmodSync,
8
+
writeFileSync,
10
9
} from "node:fs";
11
10
import { join } from "node:path";
11
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
12
12
import type { SessionData } from "../session.js";
13
13
14
14
const TEST_DIR = join(process.cwd(), ".test-session");
···
136
136
writeFileSync(
137
137
TEST_SESSION_PATH,
138
138
JSON.stringify({ accessJwt: "token" }),
139
-
"utf-8"
139
+
"utf-8",
140
140
);
141
141
142
142
const session = testLoadSession();
···
151
151
refreshJwt: "refresh",
152
152
handle: "test.bsky.social",
153
153
}),
154
-
"utf-8"
154
+
"utf-8",
155
155
);
156
156
157
157
const session = testLoadSession();