@atproto/ozone 0.2.5 → 0.2.7
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 +37 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/report/queryActivities.d.ts +4 -0
- package/dist/api/report/queryActivities.d.ts.map +1 -0
- package/dist/api/report/queryActivities.js +36 -0
- package/dist/api/report/queryActivities.js.map +1 -0
- package/dist/background.d.ts +5 -3
- package/dist/background.d.ts.map +1 -1
- package/dist/background.js +13 -4
- package/dist/background.js.map +1 -1
- package/dist/context.js +1 -1
- package/dist/context.js.map +1 -1
- package/dist/daemon/context.js +1 -1
- package/dist/daemon/context.js.map +1 -1
- package/dist/daemon/verification-listener.d.ts +1 -1
- package/dist/daemon/verification-listener.d.ts.map +1 -1
- package/dist/daemon/verification-listener.js +10 -4
- package/dist/daemon/verification-listener.js.map +1 -1
- package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.d.ts +4 -0
- package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.d.ts.map +1 -0
- package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.js +15 -0
- package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.js.map +1 -0
- package/dist/db/migrations/index.d.ts +1 -0
- package/dist/db/migrations/index.d.ts.map +1 -1
- package/dist/db/migrations/index.js +1 -0
- package/dist/db/migrations/index.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -13
- package/dist/index.js.map +1 -1
- package/dist/jetstream/service.d.ts +1 -1
- package/dist/jetstream/service.d.ts.map +1 -1
- package/dist/jetstream/service.js +3 -1
- package/dist/jetstream/service.js.map +1 -1
- package/dist/lexicon/index.d.ts +13 -0
- package/dist/lexicon/index.d.ts.map +1 -1
- package/dist/lexicon/index.js +22 -0
- package/dist/lexicon/index.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +940 -140
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +477 -69
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/app/bsky/feed/searchPostsV2.d.ts +87 -0
- package/dist/lexicon/types/app/bsky/feed/searchPostsV2.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/feed/searchPostsV2.js +5 -0
- package/dist/lexicon/types/app/bsky/feed/searchPostsV2.js.map +1 -0
- package/dist/lexicon/types/app/bsky/notification/defs.d.ts +1 -0
- package/dist/lexicon/types/app/bsky/notification/defs.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/notification/defs.js.map +1 -1
- package/dist/lexicon/types/chat/bsky/actor/declaration.d.ts +1 -1
- package/dist/lexicon/types/chat/bsky/actor/declaration.d.ts.map +1 -1
- package/dist/lexicon/types/chat/bsky/actor/declaration.js.map +1 -1
- package/dist/lexicon/types/chat/bsky/actor/defs.d.ts +2 -3
- package/dist/lexicon/types/chat/bsky/actor/defs.d.ts.map +1 -1
- package/dist/lexicon/types/chat/bsky/actor/defs.js.map +1 -1
- package/dist/lexicon/types/chat/bsky/convo/defs.d.ts +39 -36
- package/dist/lexicon/types/chat/bsky/convo/defs.d.ts.map +1 -1
- package/dist/lexicon/types/chat/bsky/convo/defs.js +7 -0
- package/dist/lexicon/types/chat/bsky/convo/defs.js.map +1 -1
- package/dist/lexicon/types/chat/bsky/convo/getUnreadCounts.d.ts +2 -2
- package/dist/lexicon/types/chat/bsky/convo/getUnreadCounts.d.ts.map +1 -1
- package/dist/lexicon/types/chat/bsky/convo/getUnreadCounts.js.map +1 -1
- package/dist/lexicon/types/chat/bsky/moderation/defs.d.ts +3 -3
- package/dist/lexicon/types/chat/bsky/moderation/defs.d.ts.map +1 -1
- package/dist/lexicon/types/chat/bsky/moderation/defs.js.map +1 -1
- package/dist/lexicon/types/chat/bsky/notification/defs.d.ts +19 -0
- package/dist/lexicon/types/chat/bsky/notification/defs.d.ts.map +1 -0
- package/dist/lexicon/types/chat/bsky/notification/defs.js +19 -0
- package/dist/lexicon/types/chat/bsky/notification/defs.js.map +1 -0
- package/dist/lexicon/types/chat/bsky/notification/getPreferences.d.ts +20 -0
- package/dist/lexicon/types/chat/bsky/notification/getPreferences.d.ts.map +1 -0
- package/dist/lexicon/types/chat/bsky/notification/getPreferences.js +5 -0
- package/dist/lexicon/types/chat/bsky/notification/getPreferences.js.map +1 -0
- package/dist/lexicon/types/chat/bsky/notification/putPreferences.d.ts +26 -0
- package/dist/lexicon/types/chat/bsky/notification/putPreferences.d.ts.map +1 -0
- package/dist/lexicon/types/chat/bsky/notification/putPreferences.js +5 -0
- package/dist/lexicon/types/chat/bsky/notification/putPreferences.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/report/defs.d.ts +1 -0
- package/dist/lexicon/types/tools/ozone/report/defs.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/report/defs.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/report/queryActivities.d.ts +32 -0
- package/dist/lexicon/types/tools/ozone/report/queryActivities.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/report/queryActivities.js +5 -0
- package/dist/lexicon/types/tools/ozone/report/queryActivities.js.map +1 -0
- package/dist/mod-service/report.d.ts +1 -0
- package/dist/mod-service/report.d.ts.map +1 -1
- package/dist/mod-service/report.js +16 -0
- package/dist/mod-service/report.js.map +1 -1
- package/dist/report/activity.d.ts +19 -1
- package/dist/report/activity.d.ts.map +1 -1
- package/dist/report/activity.js +27 -1
- package/dist/report/activity.js.map +1 -1
- package/package.json +15 -14
- package/src/api/index.ts +2 -0
- package/src/api/report/queryActivities.ts +64 -0
- package/src/background.ts +19 -4
- package/src/context.ts +1 -1
- package/src/daemon/context.ts +1 -1
- package/src/daemon/verification-listener.ts +9 -4
- package/src/db/migrations/20260602T120000000Z-add-report-activity-created-index.ts +17 -0
- package/src/db/migrations/index.ts +1 -0
- package/src/index.ts +25 -15
- package/src/jetstream/service.ts +3 -1
- package/src/mod-service/report.ts +19 -0
- package/src/report/activity.ts +47 -0
- package/tests/3p-labeler.test.ts +2 -2
- package/tests/_util.ts +8 -25
- package/tests/account-strikes.test.ts +1 -1
- package/tests/ack-all-subjects-of-account.test.ts +1 -1
- package/tests/age-assurance.test.ts +1 -1
- package/tests/blob-divert.test.ts +1 -1
- package/tests/communication-templates.test.ts +1 -1
- package/tests/content-tagger.test.ts +1 -1
- package/tests/db.test.ts +1 -1
- package/tests/expiring-label.test.ts +1 -1
- package/tests/expiring-tags.test.ts +1 -1
- package/tests/get-account-timeline.test.ts +1 -1
- package/tests/get-config.test.ts +1 -1
- package/tests/get-lists.test.ts +2 -1
- package/tests/get-profiles.test.ts +1 -1
- package/tests/get-record.test.ts +1 -1
- package/tests/get-records.test.ts +1 -1
- package/tests/get-repo.test.ts +1 -1
- package/tests/get-report.test.ts +1 -1
- package/tests/get-reporter-stats.test.ts +1 -1
- package/tests/get-repos.test.ts +1 -1
- package/tests/get-starter-pack.test.ts +1 -1
- package/tests/get-subjects.test.ts +1 -1
- package/tests/mod-tool.test.ts +1 -1
- package/tests/moderation-appeals.test.ts +1 -1
- package/tests/moderation-events.test.ts +1 -1
- package/tests/moderation-status-tags.test.ts +1 -1
- package/tests/moderation-statuses.test.ts +1 -1
- package/tests/moderation.test.ts +1 -1
- package/tests/protected-tags.test.ts +1 -1
- package/tests/query-labels.test.ts +1 -1
- package/tests/query-reports.test.ts +1 -1
- package/tests/queue-assignment.test.ts +1 -1
- package/tests/queue-router.test.ts +1 -1
- package/tests/queues.test.ts +1 -1
- package/tests/record-and-account-events.test.ts +1 -1
- package/tests/repo-search.test.ts +2 -2
- package/tests/report-action.test.ts +1 -1
- package/tests/report-activity.test.ts +145 -1
- package/tests/report-assignment.test.ts +1 -1
- package/tests/report-muting.test.ts +1 -1
- package/tests/report-reason.test.ts +1 -1
- package/tests/report-reassign-queue.test.ts +1 -1
- package/tests/report-routing.test.ts +1 -1
- package/tests/report-stats.test.ts +1 -1
- package/tests/revoke-account-credentials.test.ts +1 -1
- package/tests/safelink.test.ts +1 -1
- package/tests/scheduled-action-processor.test.ts +1 -1
- package/tests/scheduled-action.test.ts +1 -1
- package/tests/sequencer.test.ts +1 -1
- package/tests/server.test.ts +9 -12
- package/tests/sets.test.ts +1 -1
- package/tests/settings.test.ts +1 -1
- package/tests/strike-expiry-processor.test.ts +1 -1
- package/tests/subject-priority-score.test.ts +1 -1
- package/tests/takedown.test.ts +1 -1
- package/tests/team.test.ts +1 -1
- package/tests/verification-listener.test.ts +40 -13
- package/tests/verification.test.ts +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
package/src/api/index.ts
CHANGED
|
@@ -41,6 +41,7 @@ import getLatestReport from './report/getLatestReport.js'
|
|
|
41
41
|
import getLiveStats from './report/getLiveStats.js'
|
|
42
42
|
import getReport from './report/getReport.js'
|
|
43
43
|
import listActivities from './report/listActivities.js'
|
|
44
|
+
import queryActivities from './report/queryActivities.js'
|
|
44
45
|
import queryReports from './report/queryReports.js'
|
|
45
46
|
import reassignQueue from './report/reassignQueue.js'
|
|
46
47
|
import refreshStats from './report/refreshStats.js'
|
|
@@ -139,6 +140,7 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
139
140
|
getReportAssignments(server, ctx)
|
|
140
141
|
createActivity(server, ctx)
|
|
141
142
|
listActivities(server, ctx)
|
|
143
|
+
queryActivities(server, ctx)
|
|
142
144
|
reassignQueue(server, ctx)
|
|
143
145
|
return server
|
|
144
146
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { AppContext } from '../../context.js'
|
|
2
|
+
import { Server } from '../../lexicon/index.js'
|
|
3
|
+
import { ReportView } from '../../lexicon/types/tools/ozone/report/defs.js'
|
|
4
|
+
import { getReportsByIds } from '../../mod-service/report.js'
|
|
5
|
+
import {
|
|
6
|
+
formatActivityView,
|
|
7
|
+
queryReportActivities,
|
|
8
|
+
} from '../../report/activity.js'
|
|
9
|
+
import { buildReportView, hydrateReportInfo } from '../../report/views.js'
|
|
10
|
+
import { getPdsAccountInfos } from '../util.js'
|
|
11
|
+
|
|
12
|
+
export default function (server: Server, ctx: AppContext) {
|
|
13
|
+
server.tools.ozone.report.queryActivities({
|
|
14
|
+
auth: ctx.authVerifier.modOrAdminToken,
|
|
15
|
+
handler: async ({ params, auth, req }) => {
|
|
16
|
+
const db = ctx.db
|
|
17
|
+
const modService = ctx.modService(db)
|
|
18
|
+
const labelers = ctx.reqLabelers(req)
|
|
19
|
+
|
|
20
|
+
const { activities, cursor: nextCursor } = await queryReportActivities(
|
|
21
|
+
db,
|
|
22
|
+
params,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
// Dedupe report IDs across the page. Many activities can share the
|
|
26
|
+
// same report so we want one bulk fetch + hydrate rather than N.
|
|
27
|
+
const reportIds = Array.from(new Set(activities.map((a) => a.reportId)))
|
|
28
|
+
|
|
29
|
+
const queueService = ctx.queueService(db)
|
|
30
|
+
const teamService = ctx.teamService(db)
|
|
31
|
+
const reports = await getReportsByIds(db, reportIds)
|
|
32
|
+
const hydrated = await hydrateReportInfo(
|
|
33
|
+
reports,
|
|
34
|
+
modService.views,
|
|
35
|
+
(dids) => getPdsAccountInfos(ctx, dids),
|
|
36
|
+
(queueIds) => queueService.getViewsByIds(queueIds),
|
|
37
|
+
(dids) => teamService.viewByDids(dids),
|
|
38
|
+
labelers,
|
|
39
|
+
)
|
|
40
|
+
const reportViews = new Map<number, ReportView>()
|
|
41
|
+
for (const report of reports) {
|
|
42
|
+
reportViews.set(
|
|
43
|
+
report.id,
|
|
44
|
+
buildReportView(report, hydrated, auth.credentials.isModerator),
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const createdByDids = Array.from(
|
|
49
|
+
new Set(activities.map((a) => a.createdBy)),
|
|
50
|
+
)
|
|
51
|
+
const memberViews = await teamService.viewByDids(createdByDids)
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
encoding: 'application/json',
|
|
55
|
+
body: {
|
|
56
|
+
activities: activities.map((activity) =>
|
|
57
|
+
formatActivityView(activity, memberViews, reportViews),
|
|
58
|
+
),
|
|
59
|
+
cursor: nextCursor,
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
}
|
package/src/background.ts
CHANGED
|
@@ -9,9 +9,19 @@ import {
|
|
|
9
9
|
|
|
10
10
|
type Task = (db: Database, signal: AbortSignal) => Promise<void>
|
|
11
11
|
|
|
12
|
+
export type BackgroundQueueOptions = NonNullable<
|
|
13
|
+
ConstructorParameters<typeof PQueue>[0]
|
|
14
|
+
> & {
|
|
15
|
+
concurrency: number
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
/**
|
|
13
19
|
* A simple queue for in-process, out-of-band/backgrounded work
|
|
14
20
|
*/
|
|
21
|
+
// @NOTE Keep this in sync with the BackgroundQueue in
|
|
22
|
+
// - packages/bsky/src/data-plane/server/background.ts
|
|
23
|
+
// - packages/ozone/src/background.ts
|
|
24
|
+
// - packages/pds/src/background.ts
|
|
15
25
|
export class BackgroundQueue {
|
|
16
26
|
private abortController = new AbortController()
|
|
17
27
|
private queue: PQueue
|
|
@@ -26,9 +36,9 @@ export class BackgroundQueue {
|
|
|
26
36
|
|
|
27
37
|
constructor(
|
|
28
38
|
protected db: Database,
|
|
29
|
-
|
|
39
|
+
options: BackgroundQueueOptions,
|
|
30
40
|
) {
|
|
31
|
-
this.queue = new PQueue(
|
|
41
|
+
this.queue = new PQueue(options)
|
|
32
42
|
}
|
|
33
43
|
|
|
34
44
|
getStats() {
|
|
@@ -76,7 +86,8 @@ export class BackgroundQueue {
|
|
|
76
86
|
}
|
|
77
87
|
|
|
78
88
|
async processAll() {
|
|
79
|
-
|
|
89
|
+
const { queue } = this
|
|
90
|
+
while (queue.size || queue.pending) await queue.onIdle()
|
|
80
91
|
}
|
|
81
92
|
|
|
82
93
|
/**
|
|
@@ -86,8 +97,12 @@ export class BackgroundQueue {
|
|
|
86
97
|
* only once http connections have drained (tasks no longer being added).
|
|
87
98
|
*/
|
|
88
99
|
async destroy() {
|
|
100
|
+
if (this.destroyed) {
|
|
101
|
+
dbLogger.warn('BackgroundQueue.destroy() called multiple times')
|
|
102
|
+
}
|
|
103
|
+
|
|
89
104
|
this.abortController.abort()
|
|
90
|
-
|
|
105
|
+
return this.processAll()
|
|
91
106
|
}
|
|
92
107
|
}
|
|
93
108
|
|
package/src/context.ts
CHANGED
|
@@ -135,7 +135,7 @@ export class AppContext {
|
|
|
135
135
|
keypair: signingKey,
|
|
136
136
|
})
|
|
137
137
|
|
|
138
|
-
const backgroundQueue = new BackgroundQueue(db)
|
|
138
|
+
const backgroundQueue = new BackgroundQueue(db, { concurrency: 20 })
|
|
139
139
|
const blobDiverter = cfg.blobDivert
|
|
140
140
|
? new BlobDiverter(db, {
|
|
141
141
|
idResolver,
|
package/src/daemon/context.ts
CHANGED
|
@@ -73,7 +73,7 @@ export class DaemonContext {
|
|
|
73
73
|
pds: cfg.pds ?? undefined,
|
|
74
74
|
})
|
|
75
75
|
|
|
76
|
-
const backgroundQueue = new BackgroundQueue(db)
|
|
76
|
+
const backgroundQueue = new BackgroundQueue(db, { concurrency: 20 })
|
|
77
77
|
|
|
78
78
|
const settingService = SettingService.creator()
|
|
79
79
|
const strikeService = StrikeService.creator()
|
|
@@ -156,9 +156,14 @@ export class VerificationListener {
|
|
|
156
156
|
})
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
stop() {
|
|
160
|
-
this.
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
async stop() {
|
|
160
|
+
if (!this.destroyed) {
|
|
161
|
+
this.destroyed = true
|
|
162
|
+
try {
|
|
163
|
+
await this.jetstream?.close()
|
|
164
|
+
} finally {
|
|
165
|
+
await this.backgroundQueue.destroy()
|
|
166
|
+
}
|
|
167
|
+
}
|
|
163
168
|
}
|
|
164
169
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Kysely } from 'kysely'
|
|
2
|
+
|
|
3
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
4
|
+
// Supports time-ordered scans across all reports for downstream pollers
|
|
5
|
+
// (e.g. Nimbus' report-activity watcher). The existing indexes are all
|
|
6
|
+
// leading-`reportId`, which would force a sequential scan for global
|
|
7
|
+
// ordered queries.
|
|
8
|
+
await db.schema
|
|
9
|
+
.createIndex('idx_report_activity_created')
|
|
10
|
+
.on('report_activity')
|
|
11
|
+
.columns(['createdAt', 'id'])
|
|
12
|
+
.execute()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
16
|
+
await db.schema.dropIndex('idx_report_activity_created').execute()
|
|
17
|
+
}
|
|
@@ -41,3 +41,4 @@ export * as _20260313T000000000Z from './20260313T000000000Z-add-report-activity
|
|
|
41
41
|
export * as _20260318T152058935Z from './20260318T152058935Z-add-report-stat.js'
|
|
42
42
|
export * as _20260428T000000000Z from './20260428T000000000Z-add-expiring-tag-table.js'
|
|
43
43
|
export * as _20260513T202941104Z from './20260513T202941104Z-add-subject-convo-id.js'
|
|
44
|
+
export * as _20260602T120000000Z from './20260602T120000000Z-add-report-activity-created-index.js'
|
package/src/index.ts
CHANGED
|
@@ -4,11 +4,8 @@ import { AddressInfo } from 'node:net'
|
|
|
4
4
|
import compression from 'compression'
|
|
5
5
|
import cors from 'cors'
|
|
6
6
|
import express from 'express'
|
|
7
|
-
// eslint-disable-next-line import/default
|
|
7
|
+
// eslint-disable-next-line import/default
|
|
8
8
|
import httpTerminator from 'http-terminator'
|
|
9
|
-
// eslint-disable-next-line import/no-named-as-default-member
|
|
10
|
-
const { createHttpTerminator } = httpTerminator
|
|
11
|
-
type HttpTerminator = ReturnType<typeof createHttpTerminator>
|
|
12
9
|
import { DAY, SECOND } from '@atproto/common'
|
|
13
10
|
import API, { health, wellKnown } from './api/index.js'
|
|
14
11
|
import { OzoneConfig, OzoneSecrets } from './config/index.js'
|
|
@@ -29,7 +26,7 @@ export class OzoneService {
|
|
|
29
26
|
public ctx: AppContext
|
|
30
27
|
public app: express.Application
|
|
31
28
|
public server?: http.Server
|
|
32
|
-
private terminator?: HttpTerminator
|
|
29
|
+
private terminator?: httpTerminator.HttpTerminator
|
|
33
30
|
private dbStatsInterval?: NodeJS.Timeout
|
|
34
31
|
|
|
35
32
|
constructor(opts: { ctx: AppContext; app: express.Application }) {
|
|
@@ -108,23 +105,25 @@ export class OzoneService {
|
|
|
108
105
|
// so we need to sync them from env var to the database
|
|
109
106
|
await this.seedInitialMembers()
|
|
110
107
|
|
|
111
|
-
const { db, backgroundQueue } = this.ctx
|
|
112
108
|
this.dbStatsInterval = setInterval(() => {
|
|
113
109
|
dbLogger.info(
|
|
114
110
|
{
|
|
115
|
-
idleCount: db.pool.idleCount,
|
|
116
|
-
totalCount: db.pool.totalCount,
|
|
117
|
-
waitingCount: db.pool.waitingCount,
|
|
111
|
+
idleCount: this.ctx.db.pool.idleCount,
|
|
112
|
+
totalCount: this.ctx.db.pool.totalCount,
|
|
113
|
+
waitingCount: this.ctx.db.pool.waitingCount,
|
|
118
114
|
},
|
|
119
115
|
'db pool stats',
|
|
120
116
|
)
|
|
121
|
-
dbLogger.info(
|
|
117
|
+
dbLogger.info(
|
|
118
|
+
this.ctx.backgroundQueue.getStats(),
|
|
119
|
+
'background queue stats',
|
|
120
|
+
)
|
|
122
121
|
}, 10000)
|
|
123
122
|
await this.ctx.sequencer.start()
|
|
124
123
|
const server = this.app.listen(this.ctx.cfg.service.port)
|
|
125
124
|
this.server = server
|
|
126
125
|
server.keepAliveTimeout = 90000
|
|
127
|
-
this.terminator = createHttpTerminator({ server })
|
|
126
|
+
this.terminator = httpTerminator.createHttpTerminator({ server })
|
|
128
127
|
await events.once(server, 'listening')
|
|
129
128
|
const { port } = server.address() as AddressInfo
|
|
130
129
|
this.ctx.assignPort(port)
|
|
@@ -132,12 +131,23 @@ export class OzoneService {
|
|
|
132
131
|
}
|
|
133
132
|
|
|
134
133
|
async destroy(): Promise<void> {
|
|
135
|
-
await this.terminator?.terminate()
|
|
136
|
-
await this.ctx.backgroundQueue.destroy()
|
|
137
|
-
await this.ctx.sequencer.destroy()
|
|
138
|
-
await this.ctx.db.close()
|
|
139
134
|
clearInterval(this.dbStatsInterval)
|
|
140
135
|
this.dbStatsInterval = undefined
|
|
136
|
+
|
|
137
|
+
// @TODO Use a disposable stack when Node24 becomes the min supported version
|
|
138
|
+
try {
|
|
139
|
+
await this.terminator?.terminate()
|
|
140
|
+
} finally {
|
|
141
|
+
try {
|
|
142
|
+
await this.ctx.backgroundQueue.destroy()
|
|
143
|
+
} finally {
|
|
144
|
+
try {
|
|
145
|
+
await this.ctx.sequencer.destroy()
|
|
146
|
+
} finally {
|
|
147
|
+
await this.ctx.db.close()
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
141
151
|
}
|
|
142
152
|
}
|
|
143
153
|
|
package/src/jetstream/service.ts
CHANGED
|
@@ -175,6 +175,25 @@ export async function getReportById(
|
|
|
175
175
|
.executeTakeFirst()
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
export async function getReportsByIds(
|
|
179
|
+
db: Database,
|
|
180
|
+
ids: number[],
|
|
181
|
+
): Promise<ReportWithEvent[]> {
|
|
182
|
+
if (!ids.length) return []
|
|
183
|
+
return reportQuery(db)
|
|
184
|
+
.where('r.id', 'in', ids)
|
|
185
|
+
.selectAll('r')
|
|
186
|
+
.select([
|
|
187
|
+
'me.subjectDid',
|
|
188
|
+
'me.subjectUri',
|
|
189
|
+
'me.subjectCid',
|
|
190
|
+
'me.createdBy as reportedBy',
|
|
191
|
+
'me.comment',
|
|
192
|
+
'me.meta',
|
|
193
|
+
])
|
|
194
|
+
.execute()
|
|
195
|
+
}
|
|
196
|
+
|
|
178
197
|
export async function getLatestReport(
|
|
179
198
|
db: Database,
|
|
180
199
|
): Promise<ReportWithEvent | undefined> {
|
package/src/report/activity.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
2
2
|
import { Database } from '../db/index.js'
|
|
3
|
+
import { TimeIdKeyset, paginate } from '../db/pagination.js'
|
|
4
|
+
import { ReportView } from '../lexicon/types/tools/ozone/report/defs.js'
|
|
5
|
+
import { QueryParams as QueryActivitiesParams } from '../lexicon/types/tools/ozone/report/queryActivities.js'
|
|
3
6
|
import { Member } from '../lexicon/types/tools/ozone/team/defs.js'
|
|
4
7
|
import {
|
|
5
8
|
AlreadyInTargetState,
|
|
@@ -190,6 +193,48 @@ export async function listReportActivities(
|
|
|
190
193
|
return { activities, cursor: nextCursor }
|
|
191
194
|
}
|
|
192
195
|
|
|
196
|
+
export async function queryReportActivities(
|
|
197
|
+
db: Database,
|
|
198
|
+
params: QueryActivitiesParams,
|
|
199
|
+
) {
|
|
200
|
+
const {
|
|
201
|
+
activityTypes,
|
|
202
|
+
createdAfter,
|
|
203
|
+
createdBefore,
|
|
204
|
+
sortDirection,
|
|
205
|
+
limit,
|
|
206
|
+
cursor,
|
|
207
|
+
} = params
|
|
208
|
+
const { ref } = db.db.dynamic
|
|
209
|
+
|
|
210
|
+
let builder = db.db.selectFrom('report_activity').selectAll()
|
|
211
|
+
|
|
212
|
+
if (activityTypes && activityTypes.length > 0) {
|
|
213
|
+
builder = builder.where('activityType', 'in', activityTypes)
|
|
214
|
+
}
|
|
215
|
+
if (createdAfter) {
|
|
216
|
+
builder = builder.where('createdAt', '>=', createdAfter)
|
|
217
|
+
}
|
|
218
|
+
if (createdBefore) {
|
|
219
|
+
builder = builder.where('createdAt', '<=', createdBefore)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const keyset = new TimeIdKeyset(
|
|
223
|
+
ref('report_activity.createdAt'),
|
|
224
|
+
ref('report_activity.id'),
|
|
225
|
+
)
|
|
226
|
+
const paginatedBuilder = paginate(builder, {
|
|
227
|
+
limit,
|
|
228
|
+
cursor,
|
|
229
|
+
keyset,
|
|
230
|
+
direction: sortDirection,
|
|
231
|
+
tryIndex: true,
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
const activities = await paginatedBuilder.execute()
|
|
235
|
+
return { activities, cursor: keyset.packFromResult(activities) }
|
|
236
|
+
}
|
|
237
|
+
|
|
193
238
|
function buildActivityObject(
|
|
194
239
|
activityType: string,
|
|
195
240
|
previousStatus: string | null,
|
|
@@ -215,6 +260,7 @@ export function formatActivityView(
|
|
|
215
260
|
createdAt: string
|
|
216
261
|
},
|
|
217
262
|
memberViews?: Map<string, Member>,
|
|
263
|
+
reportViews?: Map<number, ReportView>,
|
|
218
264
|
) {
|
|
219
265
|
return {
|
|
220
266
|
id: activity.id,
|
|
@@ -229,6 +275,7 @@ export function formatActivityView(
|
|
|
229
275
|
isAutomated: activity.isAutomated,
|
|
230
276
|
createdBy: activity.createdBy,
|
|
231
277
|
moderator: memberViews?.get(activity.createdBy),
|
|
278
|
+
report: reportViews?.get(activity.reportId),
|
|
232
279
|
createdAt: activity.createdAt,
|
|
233
280
|
}
|
|
234
281
|
}
|
package/tests/3p-labeler.test.ts
CHANGED
package/tests/_util.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RequestListener, createServer } from 'node:http'
|
|
2
2
|
import { AddressInfo } from 'node:net'
|
|
3
|
-
|
|
3
|
+
// eslint-disable-next-line import/default
|
|
4
|
+
import httpTerminator from 'http-terminator'
|
|
4
5
|
import { CID } from 'multiformats/cid'
|
|
5
6
|
import { lexToJson } from '@atproto/lexicon'
|
|
6
7
|
import { AtUri } from '@atproto/syntax'
|
|
@@ -215,19 +216,11 @@ export const stripViewerFromThread = <T extends ThreadViewPost>(
|
|
|
215
216
|
return thread
|
|
216
217
|
}
|
|
217
218
|
|
|
218
|
-
export async function startServer(
|
|
219
|
-
return new Promise<{
|
|
220
|
-
origin: string
|
|
221
|
-
server: Server
|
|
222
|
-
stop: () => Promise<void>
|
|
223
|
-
}>((resolve, reject) => {
|
|
219
|
+
export async function startServer(listener: RequestListener) {
|
|
220
|
+
return new Promise<AsyncDisposable & { port: number }>((resolve, reject) => {
|
|
224
221
|
const onListen = () => {
|
|
225
222
|
const port = (server.address() as AddressInfo).port
|
|
226
|
-
resolve({
|
|
227
|
-
server,
|
|
228
|
-
origin: `http://localhost:${port}`,
|
|
229
|
-
stop: () => stopServer(server),
|
|
230
|
-
})
|
|
223
|
+
resolve({ port, [Symbol.asyncDispose]: () => terminator.terminate() })
|
|
231
224
|
cleanup()
|
|
232
225
|
}
|
|
233
226
|
const onError = (err: Error) => {
|
|
@@ -239,21 +232,11 @@ export async function startServer(app: Express) {
|
|
|
239
232
|
server.removeListener('error', onError)
|
|
240
233
|
}
|
|
241
234
|
|
|
242
|
-
const server =
|
|
235
|
+
const server = createServer(listener)
|
|
243
236
|
.listen(0)
|
|
244
237
|
.once('listening', onListen)
|
|
245
238
|
.once('error', onError)
|
|
246
|
-
})
|
|
247
|
-
}
|
|
248
239
|
|
|
249
|
-
|
|
250
|
-
return new Promise<void>((resolve, reject) => {
|
|
251
|
-
server.close((err) => {
|
|
252
|
-
if (err) {
|
|
253
|
-
reject(err)
|
|
254
|
-
} else {
|
|
255
|
-
resolve()
|
|
256
|
-
}
|
|
257
|
-
})
|
|
240
|
+
const terminator = httpTerminator.createHttpTerminator({ server })
|
|
258
241
|
})
|
|
259
242
|
}
|
package/tests/db.test.ts
CHANGED
package/tests/get-config.test.ts
CHANGED
package/tests/get-lists.test.ts
CHANGED
|
@@ -35,8 +35,9 @@ describe('admin get lists', () => {
|
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
afterAll(async () => {
|
|
38
|
+
// @TODO figure out why we even need this in afterAll ?
|
|
38
39
|
AtpAgent.configure({ appLabelers: [BSKY_LABELER_DID] })
|
|
39
|
-
await network
|
|
40
|
+
await network?.close()
|
|
40
41
|
})
|
|
41
42
|
|
|
42
43
|
const getAlicesList = async () => {
|
package/tests/get-record.test.ts
CHANGED
package/tests/get-repo.test.ts
CHANGED
package/tests/get-report.test.ts
CHANGED
package/tests/get-repos.test.ts
CHANGED