@atproto/ozone 0.1.150 → 0.1.152

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 (118) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/api/moderation/queryEvents.d.ts.map +1 -1
  3. package/dist/api/moderation/queryEvents.js +2 -1
  4. package/dist/api/moderation/queryEvents.js.map +1 -1
  5. package/dist/context.d.ts +3 -0
  6. package/dist/context.d.ts.map +1 -1
  7. package/dist/context.js +7 -1
  8. package/dist/context.js.map +1 -1
  9. package/dist/daemon/context.d.ts +3 -0
  10. package/dist/daemon/context.d.ts.map +1 -1
  11. package/dist/daemon/context.js +11 -1
  12. package/dist/daemon/context.js.map +1 -1
  13. package/dist/daemon/index.d.ts +1 -0
  14. package/dist/daemon/index.d.ts.map +1 -1
  15. package/dist/daemon/index.js +3 -1
  16. package/dist/daemon/index.js.map +1 -1
  17. package/dist/daemon/strike-expiry-processor.d.ts +18 -0
  18. package/dist/daemon/strike-expiry-processor.d.ts.map +1 -0
  19. package/dist/daemon/strike-expiry-processor.js +111 -0
  20. package/dist/daemon/strike-expiry-processor.js.map +1 -0
  21. package/dist/db/migrations/20251008T120000000Z-add-strike-system.d.ts +4 -0
  22. package/dist/db/migrations/20251008T120000000Z-add-strike-system.d.ts.map +1 -0
  23. package/dist/db/migrations/20251008T120000000Z-add-strike-system.js +75 -0
  24. package/dist/db/migrations/20251008T120000000Z-add-strike-system.js.map +1 -0
  25. package/dist/db/migrations/index.d.ts +1 -0
  26. package/dist/db/migrations/index.d.ts.map +1 -1
  27. package/dist/db/migrations/index.js +2 -1
  28. package/dist/db/migrations/index.js.map +1 -1
  29. package/dist/db/schema/account_strike.d.ts +12 -0
  30. package/dist/db/schema/account_strike.d.ts.map +1 -0
  31. package/dist/db/schema/account_strike.js +5 -0
  32. package/dist/db/schema/account_strike.js.map +1 -0
  33. package/dist/db/schema/index.d.ts +3 -1
  34. package/dist/db/schema/index.d.ts.map +1 -1
  35. package/dist/db/schema/index.js.map +1 -1
  36. package/dist/db/schema/job_cursor.d.ts +11 -0
  37. package/dist/db/schema/job_cursor.d.ts.map +1 -0
  38. package/dist/db/schema/job_cursor.js +5 -0
  39. package/dist/db/schema/job_cursor.js.map +1 -0
  40. package/dist/db/schema/moderation_event.d.ts +3 -0
  41. package/dist/db/schema/moderation_event.d.ts.map +1 -1
  42. package/dist/db/schema/moderation_event.js.map +1 -1
  43. package/dist/lexicon/lexicons.d.ts +208 -0
  44. package/dist/lexicon/lexicons.d.ts.map +1 -1
  45. package/dist/lexicon/lexicons.js +104 -0
  46. package/dist/lexicon/lexicons.js.map +1 -1
  47. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +12 -0
  48. package/dist/lexicon/types/app/bsky/actor/defs.d.ts.map +1 -1
  49. package/dist/lexicon/types/app/bsky/actor/defs.js.map +1 -1
  50. package/dist/lexicon/types/app/bsky/feed/defs.d.ts +4 -0
  51. package/dist/lexicon/types/app/bsky/feed/defs.d.ts.map +1 -1
  52. package/dist/lexicon/types/app/bsky/feed/defs.js.map +1 -1
  53. package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts +35 -0
  54. package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts.map +1 -1
  55. package/dist/lexicon/types/tools/ozone/moderation/defs.js +9 -0
  56. package/dist/lexicon/types/tools/ozone/moderation/defs.js.map +1 -1
  57. package/dist/lexicon/types/tools/ozone/moderation/queryEvents.d.ts +2 -0
  58. package/dist/lexicon/types/tools/ozone/moderation/queryEvents.d.ts.map +1 -1
  59. package/dist/lexicon/types/tools/ozone/moderation/queryEvents.js.map +1 -1
  60. package/dist/lexicon/types/tools/ozone/moderation/queryStatuses.d.ts +2 -0
  61. package/dist/lexicon/types/tools/ozone/moderation/queryStatuses.d.ts.map +1 -1
  62. package/dist/lexicon/types/tools/ozone/moderation/queryStatuses.js.map +1 -1
  63. package/dist/mod-service/index.d.ts +9 -3
  64. package/dist/mod-service/index.d.ts.map +1 -1
  65. package/dist/mod-service/index.js +59 -6
  66. package/dist/mod-service/index.js.map +1 -1
  67. package/dist/mod-service/status.d.ts +44 -2
  68. package/dist/mod-service/status.d.ts.map +1 -1
  69. package/dist/mod-service/status.js +7 -0
  70. package/dist/mod-service/status.js.map +1 -1
  71. package/dist/mod-service/strike.d.ts +19 -0
  72. package/dist/mod-service/strike.d.ts.map +1 -0
  73. package/dist/mod-service/strike.js +86 -0
  74. package/dist/mod-service/strike.js.map +1 -0
  75. package/dist/mod-service/types.d.ts +4 -0
  76. package/dist/mod-service/types.d.ts.map +1 -1
  77. package/dist/mod-service/types.js.map +1 -1
  78. package/dist/mod-service/views.d.ts.map +1 -1
  79. package/dist/mod-service/views.js +20 -4
  80. package/dist/mod-service/views.js.map +1 -1
  81. package/dist/setting/constants.d.ts +1 -0
  82. package/dist/setting/constants.d.ts.map +1 -1
  83. package/dist/setting/constants.js +2 -1
  84. package/dist/setting/constants.js.map +1 -1
  85. package/dist/setting/validators.d.ts.map +1 -1
  86. package/dist/setting/validators.js +179 -0
  87. package/dist/setting/validators.js.map +1 -1
  88. package/package.json +3 -3
  89. package/src/api/moderation/queryEvents.ts +2 -0
  90. package/src/context.ts +20 -11
  91. package/src/daemon/context.ts +15 -1
  92. package/src/daemon/index.ts +1 -0
  93. package/src/daemon/strike-expiry-processor.ts +111 -0
  94. package/src/db/migrations/20251008T120000000Z-add-strike-system.ts +87 -0
  95. package/src/db/migrations/index.ts +1 -0
  96. package/src/db/schema/account_strike.ts +13 -0
  97. package/src/db/schema/index.ts +4 -0
  98. package/src/db/schema/job_cursor.ts +13 -0
  99. package/src/db/schema/moderation_event.ts +3 -0
  100. package/src/lexicon/lexicons.ts +119 -0
  101. package/src/lexicon/types/app/bsky/actor/defs.ts +6 -0
  102. package/src/lexicon/types/app/bsky/feed/defs.ts +2 -0
  103. package/src/lexicon/types/tools/ozone/moderation/defs.ts +44 -0
  104. package/src/lexicon/types/tools/ozone/moderation/queryEvents.ts +2 -0
  105. package/src/lexicon/types/tools/ozone/moderation/queryStatuses.ts +2 -0
  106. package/src/mod-service/index.ts +70 -3
  107. package/src/mod-service/status.ts +9 -0
  108. package/src/mod-service/strike.ts +96 -0
  109. package/src/mod-service/types.ts +6 -0
  110. package/src/mod-service/views.ts +25 -4
  111. package/src/setting/constants.ts +1 -0
  112. package/src/setting/validators.ts +231 -1
  113. package/tests/__snapshots__/account-strikes.test.ts.snap +159 -0
  114. package/tests/account-strikes.test.ts +184 -0
  115. package/tests/query-labels.test.ts +1 -0
  116. package/tests/strike-expiry-processor.test.ts +299 -0
  117. package/tsconfig.build.tsbuildinfo +1 -1
  118. package/tsconfig.tests.tsbuildinfo +1 -1
package/src/context.ts CHANGED
@@ -21,6 +21,7 @@ import {
21
21
  ModerationServiceProfile,
22
22
  ModerationServiceProfileCreator,
23
23
  } from './mod-service/profile'
24
+ import { StrikeService, StrikeServiceCreator } from './mod-service/strike'
24
25
  import {
25
26
  SafelinkRuleService,
26
27
  SafelinkRuleServiceCreator,
@@ -59,6 +60,7 @@ export type AppContextOptions = {
59
60
  scheduledActionService: ScheduledActionServiceCreator
60
61
  setService: SetServiceCreator
61
62
  settingService: SettingServiceCreator
63
+ strikeService: StrikeServiceCreator
62
64
  teamService: TeamServiceCreator
63
65
  appviewAgent: AtpAgent
64
66
  pdsAgent: AtpAgent | undefined
@@ -132,17 +134,6 @@ export class AppContext {
132
134
  appview: cfg.appview.pushEvents ? cfg.appview : undefined,
133
135
  pds: cfg.pds ?? undefined,
134
136
  })
135
- const modService = ModerationService.creator(
136
- signingKey,
137
- signingKeyId,
138
- cfg,
139
- backgroundQueue,
140
- idResolver,
141
- eventPusher,
142
- appviewAgent,
143
- createAuthHeaders,
144
- overrides?.imgInvalidator,
145
- )
146
137
 
147
138
  const communicationTemplateService = CommunicationTemplateService.creator()
148
139
  const safelinkRuleService = SafelinkRuleService.creator()
@@ -154,12 +145,25 @@ export class AppContext {
154
145
  )
155
146
  const setService = SetService.creator()
156
147
  const settingService = SettingService.creator()
148
+ const strikeService = StrikeService.creator()
157
149
  const verificationService = VerificationService.creator()
158
150
  const verificationIssuer = VerificationIssuer.creator()
159
151
  const moderationServiceProfile = ModerationServiceProfile.creator(
160
152
  cfg,
161
153
  appviewAgent,
162
154
  )
155
+ const modService = ModerationService.creator(
156
+ signingKey,
157
+ signingKeyId,
158
+ cfg,
159
+ backgroundQueue,
160
+ idResolver,
161
+ eventPusher,
162
+ appviewAgent,
163
+ createAuthHeaders,
164
+ strikeService,
165
+ overrides?.imgInvalidator,
166
+ )
163
167
 
164
168
  const sequencer = new Sequencer(modService(db))
165
169
 
@@ -181,6 +185,7 @@ export class AppContext {
181
185
  teamService,
182
186
  setService,
183
187
  settingService,
188
+ strikeService,
184
189
  appviewAgent,
185
190
  pdsAgent,
186
191
  chatAgent,
@@ -248,6 +253,10 @@ export class AppContext {
248
253
  return this.opts.settingService
249
254
  }
250
255
 
256
+ get strikeService(): StrikeServiceCreator {
257
+ return this.opts.strikeService
258
+ }
259
+
251
260
  get verificationService(): VerificationServiceCreator {
252
261
  return this.opts.verificationService
253
262
  }
@@ -7,6 +7,7 @@ import { BackgroundQueue } from '../background'
7
7
  import { OzoneConfig, OzoneSecrets } from '../config'
8
8
  import { Database } from '../db'
9
9
  import { ModerationService } from '../mod-service'
10
+ import { StrikeService } from '../mod-service/strike'
10
11
  import { ScheduledActionService } from '../scheduled-action/service'
11
12
  import { SettingService } from '../setting/service'
12
13
  import { TeamService } from '../team'
@@ -15,6 +16,7 @@ import { EventPusher } from './event-pusher'
15
16
  import { EventReverser } from './event-reverser'
16
17
  import { MaterializedViewRefresher } from './materialized-view-refresher'
17
18
  import { ScheduledActionProcessor } from './scheduled-action-processor'
19
+ import { StrikeExpiryProcessor } from './strike-expiry-processor'
18
20
  import { TeamProfileSynchronizer } from './team-profile-synchronizer'
19
21
  import { VerificationListener } from './verification-listener'
20
22
 
@@ -28,6 +30,7 @@ export type DaemonContextOptions = {
28
30
  materializedViewRefresher: MaterializedViewRefresher
29
31
  teamProfileSynchronizer: TeamProfileSynchronizer
30
32
  scheduledActionProcessor: ScheduledActionProcessor
33
+ strikeExpiryProcessor: StrikeExpiryProcessor
31
34
  verificationListener?: VerificationListener
32
35
  }
33
36
 
@@ -66,6 +69,8 @@ export class DaemonContext {
66
69
 
67
70
  const backgroundQueue = new BackgroundQueue(db)
68
71
 
72
+ const settingService = SettingService.creator()
73
+ const strikeService = StrikeService.creator()
69
74
  const modService = ModerationService.creator(
70
75
  signingKey,
71
76
  signingKeyId,
@@ -75,8 +80,8 @@ export class DaemonContext {
75
80
  eventPusher,
76
81
  appviewAgent,
77
82
  createAuthHeaders,
83
+ strikeService,
78
84
  )
79
- const settingService = SettingService.creator()
80
85
  const scheduledActionService = ScheduledActionService.creator()
81
86
  const teamService = TeamService.creator(
82
87
  appviewAgent,
@@ -104,6 +109,8 @@ export class DaemonContext {
104
109
  scheduledActionService,
105
110
  )
106
111
 
112
+ const strikeExpiryProcessor = new StrikeExpiryProcessor(db, strikeService)
113
+
107
114
  // Only spawn the listener if verifier config exists and a jetstream URL is provided
108
115
  const verificationListener =
109
116
  cfg.verifier && cfg.jetstreamUrl
@@ -124,6 +131,7 @@ export class DaemonContext {
124
131
  materializedViewRefresher,
125
132
  teamProfileSynchronizer,
126
133
  scheduledActionProcessor,
134
+ strikeExpiryProcessor,
127
135
  verificationListener,
128
136
  ...(overrides ?? {}),
129
137
  })
@@ -161,6 +169,10 @@ export class DaemonContext {
161
169
  return this.opts.scheduledActionProcessor
162
170
  }
163
171
 
172
+ get strikeExpiryProcessor(): StrikeExpiryProcessor {
173
+ return this.opts.strikeExpiryProcessor
174
+ }
175
+
164
176
  get verificationListener(): VerificationListener | undefined {
165
177
  return this.opts.verificationListener
166
178
  }
@@ -171,6 +183,7 @@ export class DaemonContext {
171
183
  this.materializedViewRefresher.start()
172
184
  this.teamProfileSynchronizer.start()
173
185
  this.scheduledActionProcessor.start()
186
+ this.strikeExpiryProcessor.start()
174
187
  this.verificationListener?.start()
175
188
  }
176
189
 
@@ -189,6 +202,7 @@ export class DaemonContext {
189
202
  this.materializedViewRefresher.destroy(),
190
203
  this.teamProfileSynchronizer.destroy(),
191
204
  this.scheduledActionProcessor.destroy(),
205
+ this.strikeExpiryProcessor.destroy(),
192
206
  this.verificationListener?.stop(),
193
207
  ])
194
208
  } finally {
@@ -6,6 +6,7 @@ export { EventPusher } from './event-pusher'
6
6
  export { BlobDiverter } from './blob-diverter'
7
7
  export { EventReverser } from './event-reverser'
8
8
  export { ScheduledActionProcessor } from './scheduled-action-processor'
9
+ export { StrikeExpiryProcessor } from './strike-expiry-processor'
9
10
 
10
11
  export class OzoneDaemon {
11
12
  constructor(public ctx: DaemonContext) {}
@@ -0,0 +1,111 @@
1
+ import { HOUR } from '@atproto/common'
2
+ import { Database } from '../db'
3
+ import { dbLogger } from '../logger'
4
+ import { StrikeServiceCreator } from '../mod-service/strike'
5
+
6
+ const JOB_NAME = 'strike_expiry'
7
+
8
+ export class StrikeExpiryProcessor {
9
+ destroyed = false
10
+ processingPromise: Promise<void> = Promise.resolve()
11
+ timer?: NodeJS.Timeout
12
+
13
+ constructor(
14
+ private db: Database,
15
+ private strikeServiceCreator: StrikeServiceCreator,
16
+ ) {}
17
+
18
+ start() {
19
+ this.initializeCursor().then(() => this.poll())
20
+ }
21
+
22
+ poll() {
23
+ if (this.destroyed) return
24
+ this.processingPromise = this.processExpiredStrikes()
25
+ .catch((err) =>
26
+ dbLogger.error({ err }, 'strike expiry processing errored'),
27
+ )
28
+ .finally(() => {
29
+ this.timer = setTimeout(() => this.poll(), getInterval())
30
+ })
31
+ }
32
+
33
+ async destroy() {
34
+ this.destroyed = true
35
+ if (this.timer) {
36
+ clearTimeout(this.timer)
37
+ this.timer = undefined
38
+ }
39
+ await this.processingPromise
40
+ }
41
+
42
+ async initializeCursor() {
43
+ await this.db.db
44
+ .insertInto('job_cursor')
45
+ .values({
46
+ job: JOB_NAME,
47
+ cursor: null,
48
+ })
49
+ .onConflict((oc) => oc.doNothing())
50
+ .execute()
51
+ }
52
+
53
+ async getCursor(): Promise<string | null> {
54
+ const entry = await this.db.db
55
+ .selectFrom('job_cursor')
56
+ .select('cursor')
57
+ .where('job', '=', JOB_NAME)
58
+ .executeTakeFirst()
59
+
60
+ return entry?.cursor || null
61
+ }
62
+
63
+ async updateCursor(cursor: string): Promise<void> {
64
+ await this.db.db
65
+ .updateTable('job_cursor')
66
+ .set({ cursor })
67
+ .where('job', '=', JOB_NAME)
68
+ .execute()
69
+ }
70
+
71
+ async processExpiredStrikes() {
72
+ const now = new Date()
73
+ const strikeService = this.strikeServiceCreator(this.db)
74
+ const lastProcessedAt = await this.getCursor()
75
+ const affectedSubjects = await strikeService.getExpiredStrikeSubjects(
76
+ lastProcessedAt || undefined,
77
+ )
78
+
79
+ if (!affectedSubjects.length) {
80
+ dbLogger.info('no expired strikes to process')
81
+ await this.updateCursor(now.toISOString())
82
+ return
83
+ }
84
+
85
+ dbLogger.info(
86
+ { count: affectedSubjects.length },
87
+ 'processing subjects with expired strikes',
88
+ )
89
+
90
+ await Promise.all(
91
+ affectedSubjects.map(({ subjectDid }) => {
92
+ return strikeService.updateSubjectStrikeCount(subjectDid)
93
+ }),
94
+ )
95
+
96
+ await this.updateCursor(now.toISOString())
97
+
98
+ dbLogger.info(
99
+ { processed: affectedSubjects.length },
100
+ 'strike expiry processing completed',
101
+ )
102
+ }
103
+ }
104
+
105
+ const getInterval = (): number => {
106
+ // Run every hour, synchronized to the hour boundary
107
+ const now = Date.now()
108
+ const intervalMs = HOUR
109
+ const nextIteration = Math.ceil(now / intervalMs)
110
+ return nextIteration * intervalMs - now
111
+ }
@@ -0,0 +1,87 @@
1
+ import { Kysely, sql } from 'kysely'
2
+
3
+ export async function up(db: Kysely<unknown>): Promise<void> {
4
+ await db.schema
5
+ .alterTable('moderation_event')
6
+ .addColumn('severityLevel', 'varchar')
7
+ .execute()
8
+ await db.schema
9
+ .alterTable('moderation_event')
10
+ .addColumn('strikeCount', 'integer')
11
+ .execute()
12
+ await db.schema
13
+ .alterTable('moderation_event')
14
+ .addColumn('strikeExpiresAt', 'varchar')
15
+ .execute()
16
+
17
+ await db.schema
18
+ .createTable('account_strike')
19
+ .addColumn('did', 'text', (col) => col.primaryKey())
20
+ .addColumn('firstStrikeAt', 'varchar')
21
+ .addColumn('lastStrikeAt', 'varchar')
22
+ .addColumn('activeStrikeCount', 'integer', (col) =>
23
+ col.notNull().defaultTo(0),
24
+ )
25
+ .addColumn('totalStrikeCount', 'integer', (col) =>
26
+ col.notNull().defaultTo(0),
27
+ )
28
+ .execute()
29
+
30
+ await db.schema
31
+ .createTable('job_cursor')
32
+ .addColumn('job', 'text', (col) => col.primaryKey())
33
+ .addColumn('cursor', 'text')
34
+ .addColumn('updatedAt', 'text', (col) =>
35
+ col.defaultTo(sql`now()`).notNull(),
36
+ )
37
+ .execute()
38
+
39
+ // This supports fast look up for background job that aggregates strike data per subjectDid
40
+ await db.schema
41
+ .createIndex('moderation_event_subject_did_strike_count_idx')
42
+ .on('moderation_event')
43
+ .columns(['subjectDid', 'strikeCount'])
44
+ .execute()
45
+
46
+ // This supports fast lookup in the background job that needs to find strikes that have expired
47
+ await sql`
48
+ CREATE INDEX moderation_event_strike_expires_at_strike_count_idx
49
+ ON moderation_event ("strikeExpiresAt", "strikeCount")
50
+ WHERE "strikeExpiresAt" IS NOT NULL AND "strikeCount" IS NOT NULL
51
+ `.execute(db)
52
+
53
+ // for sorting and filtering by active strike count
54
+ await db.schema
55
+ .createIndex('account_strike_active_count_idx')
56
+ .on('account_strike')
57
+ .column('activeStrikeCount')
58
+ .execute()
59
+ }
60
+
61
+ export async function down(db: Kysely<unknown>): Promise<void> {
62
+ await db.schema
63
+ .dropIndex('moderation_event_subject_did_strike_count_idx')
64
+ .execute()
65
+ await db.schema
66
+ .dropIndex('moderation_event_strike_expires_at_strike_count_idx')
67
+ .execute()
68
+ await db.schema.dropIndex('account_strike_active_count_idx').execute()
69
+
70
+ await db.schema.dropTable('account_strike').execute()
71
+ await db.schema.dropTable('job_cursor').execute()
72
+
73
+ await db.schema
74
+ .alterTable('moderation_event')
75
+ .dropColumn('severityLevel')
76
+ .execute()
77
+
78
+ await db.schema
79
+ .alterTable('moderation_event')
80
+ .dropColumn('strikeCount')
81
+ .execute()
82
+
83
+ await db.schema
84
+ .alterTable('moderation_event')
85
+ .dropColumn('strikeExpiresAt')
86
+ .execute()
87
+ }
@@ -32,3 +32,4 @@ export * as _20250715T000000000Z from './20250715T000000000Z-add-mod-event-exter
32
32
  export * as _20250718T150931000Z from './20250718T150931000Z-update-appeal-reason-stats'
33
33
  export * as _20250813T000000000Z from './20250813T000000000Z-mod-tool-batch-id-index'
34
34
  export * as _20250923T000000000Z from './20250923T000000000Z-scheduled-actions'
35
+ export * as _20251008T120000000Z from './20251008T120000000Z-add-strike-system'
@@ -0,0 +1,13 @@
1
+ export const accountStrikeTableName = 'account_strike'
2
+
3
+ export interface AccountStrike {
4
+ did: string // Primary key
5
+ firstStrikeAt: string | null
6
+ lastStrikeAt: string | null
7
+ activeStrikeCount: number
8
+ totalStrikeCount: number
9
+ }
10
+
11
+ export type PartialDB = {
12
+ [accountStrikeTableName]: AccountStrike
13
+ }
@@ -2,9 +2,11 @@ import { Kysely } from 'kysely'
2
2
  import * as accountEventsStats from './account_events_stats'
3
3
  import * as accountRecordEventsStats from './account_record_events_stats'
4
4
  import * as accountRecordStatusStats from './account_record_status_stats'
5
+ import * as accountStrike from './account_strike'
5
6
  import * as blobPushEvent from './blob_push_event'
6
7
  import * as communicationTemplate from './communication_template'
7
8
  import * as firehoseCursor from './firehose_cursor'
9
+ import * as jobCursor from './job_cursor'
8
10
  import * as label from './label'
9
11
  import * as member from './member'
10
12
  import * as modEvent from './moderation_event'
@@ -34,8 +36,10 @@ export type DatabaseSchemaType = modEvent.PartialDB &
34
36
  recordEventsStats.PartialDB &
35
37
  accountRecordEventsStats.PartialDB &
36
38
  accountRecordStatusStats.PartialDB &
39
+ accountStrike.PartialDB &
37
40
  verification.PartialDB &
38
41
  firehoseCursor.PartialDB &
42
+ jobCursor.PartialDB &
39
43
  safelink.PartialDB &
40
44
  scheduledAction.PartialDB
41
45
 
@@ -0,0 +1,13 @@
1
+ import { Generated } from 'kysely'
2
+
3
+ export const jobCursorTableName = 'job_cursor'
4
+
5
+ export interface JobCursor {
6
+ job: string
7
+ cursor: string | null
8
+ updatedAt: Generated<string>
9
+ }
10
+
11
+ export type PartialDB = {
12
+ [jobCursorTableName]: JobCursor
13
+ }
@@ -48,6 +48,9 @@ export interface ModerationEvent {
48
48
  legacyRefId: number | null
49
49
  modTool: { name: string; meta?: { [_ in string]: unknown } } | null
50
50
  externalId: string | null
51
+ severityLevel: string | null
52
+ strikeCount: number | null
53
+ strikeExpiresAt: string | null
51
54
  }
52
55
 
53
56
  export type PartialDB = {
@@ -65,6 +65,10 @@ export const schemaDict = {
65
65
  type: 'ref',
66
66
  ref: 'lex:app.bsky.actor.defs#statusView',
67
67
  },
68
+ debug: {
69
+ type: 'unknown',
70
+ description: 'Debug information for internal development',
71
+ },
68
72
  },
69
73
  },
70
74
  profileView: {
@@ -127,6 +131,10 @@ export const schemaDict = {
127
131
  type: 'ref',
128
132
  ref: 'lex:app.bsky.actor.defs#statusView',
129
133
  },
134
+ debug: {
135
+ type: 'unknown',
136
+ description: 'Debug information for internal development',
137
+ },
130
138
  },
131
139
  },
132
140
  profileViewDetailed: {
@@ -214,6 +222,10 @@ export const schemaDict = {
214
222
  type: 'ref',
215
223
  ref: 'lex:app.bsky.actor.defs#statusView',
216
224
  },
225
+ debug: {
226
+ type: 'unknown',
227
+ description: 'Debug information for internal development',
228
+ },
217
229
  },
218
230
  },
219
231
  profileAssociated: {
@@ -1846,6 +1858,10 @@ export const schemaDict = {
1846
1858
  type: 'ref',
1847
1859
  ref: 'lex:app.bsky.feed.defs#threadgateView',
1848
1860
  },
1861
+ debug: {
1862
+ type: 'unknown',
1863
+ description: 'Debug information for internal development',
1864
+ },
1849
1865
  },
1850
1866
  },
1851
1867
  viewerState: {
@@ -14630,6 +14646,12 @@ export const schemaDict = {
14630
14646
  type: 'ref',
14631
14647
  ref: 'lex:tools.ozone.moderation.defs#recordsStats',
14632
14648
  },
14649
+ accountStrike: {
14650
+ description:
14651
+ 'Strike information for the account (account-level only)',
14652
+ type: 'ref',
14653
+ ref: 'lex:tools.ozone.moderation.defs#accountStrike',
14654
+ },
14633
14655
  ageAssuranceState: {
14634
14656
  type: 'string',
14635
14657
  description: 'Current age assurance state of the subject.',
@@ -14742,6 +14764,32 @@ export const schemaDict = {
14742
14764
  },
14743
14765
  },
14744
14766
  },
14767
+ accountStrike: {
14768
+ description: 'Strike information for an account',
14769
+ type: 'object',
14770
+ properties: {
14771
+ activeStrikeCount: {
14772
+ description:
14773
+ 'Current number of active strikes (excluding expired strikes)',
14774
+ type: 'integer',
14775
+ },
14776
+ totalStrikeCount: {
14777
+ description:
14778
+ 'Total number of strikes ever received (including expired strikes)',
14779
+ type: 'integer',
14780
+ },
14781
+ firstStrikeAt: {
14782
+ description: 'Timestamp of the first strike received',
14783
+ type: 'string',
14784
+ format: 'datetime',
14785
+ },
14786
+ lastStrikeAt: {
14787
+ description: 'Timestamp of the most recent strike received',
14788
+ type: 'string',
14789
+ format: 'datetime',
14790
+ },
14791
+ },
14792
+ },
14745
14793
  subjectReviewState: {
14746
14794
  type: 'string',
14747
14795
  knownValues: [
@@ -14797,6 +14845,22 @@ export const schemaDict = {
14797
14845
  description:
14798
14846
  'Names/Keywords of the policies that drove the decision.',
14799
14847
  },
14848
+ severityLevel: {
14849
+ type: 'string',
14850
+ description:
14851
+ "Severity level of the violation (e.g., 'sev-0', 'sev-1', 'sev-2', etc.).",
14852
+ },
14853
+ strikeCount: {
14854
+ type: 'integer',
14855
+ description:
14856
+ 'Number of strikes to assign to the user for this violation.',
14857
+ },
14858
+ strikeExpiresAt: {
14859
+ type: 'string',
14860
+ format: 'datetime',
14861
+ description:
14862
+ 'When the strike should expire. If not provided, the strike never expires.',
14863
+ },
14800
14864
  },
14801
14865
  },
14802
14866
  modEventReverseTakedown: {
@@ -14807,6 +14871,25 @@ export const schemaDict = {
14807
14871
  type: 'string',
14808
14872
  description: 'Describe reasoning behind the reversal.',
14809
14873
  },
14874
+ policies: {
14875
+ type: 'array',
14876
+ maxLength: 5,
14877
+ items: {
14878
+ type: 'string',
14879
+ },
14880
+ description:
14881
+ 'Names/Keywords of the policy infraction for which takedown is being reversed.',
14882
+ },
14883
+ severityLevel: {
14884
+ type: 'string',
14885
+ description:
14886
+ "Severity level of the violation. Usually set from the last policy infraction's severity.",
14887
+ },
14888
+ strikeCount: {
14889
+ type: 'integer',
14890
+ description:
14891
+ "Number of strikes to subtract from the user's strike count. Usually set from the last policy infraction's severity.",
14892
+ },
14810
14893
  },
14811
14894
  },
14812
14895
  modEventResolveAppeal: {
@@ -15050,6 +15133,31 @@ export const schemaDict = {
15050
15133
  type: 'string',
15051
15134
  description: 'Additional comment about the outgoing comm.',
15052
15135
  },
15136
+ policies: {
15137
+ type: 'array',
15138
+ maxLength: 5,
15139
+ items: {
15140
+ type: 'string',
15141
+ },
15142
+ description:
15143
+ 'Names/Keywords of the policies that necessitated the email.',
15144
+ },
15145
+ severityLevel: {
15146
+ type: 'string',
15147
+ description:
15148
+ "Severity level of the violation. Normally 'sev-1' that adds strike on repeat offense",
15149
+ },
15150
+ strikeCount: {
15151
+ type: 'integer',
15152
+ description:
15153
+ 'Number of strikes to assign to the user for this violation. Normally 0 as an indicator of a warning and only added as a strike on a repeat offense.',
15154
+ },
15155
+ strikeExpiresAt: {
15156
+ type: 'string',
15157
+ format: 'datetime',
15158
+ description:
15159
+ 'When the strike should expire. If not provided, the strike never expires.',
15160
+ },
15053
15161
  },
15054
15162
  },
15055
15163
  modEventDivert: {
@@ -16448,6 +16556,11 @@ export const schemaDict = {
16448
16556
  'blocked',
16449
16557
  ],
16450
16558
  },
16559
+ withStrike: {
16560
+ type: 'boolean',
16561
+ description:
16562
+ 'If specified, only events where strikeCount value is set are returned.',
16563
+ },
16451
16564
  cursor: {
16452
16565
  type: 'string',
16453
16566
  },
@@ -16678,6 +16791,12 @@ export const schemaDict = {
16678
16791
  description:
16679
16792
  'If specified, only subjects that have priority score value above the given value will be returned.',
16680
16793
  },
16794
+ minStrikeCount: {
16795
+ type: 'integer',
16796
+ minimum: 1,
16797
+ description:
16798
+ 'If specified, only subjects that belong to an account that has at least this many active strikes will be returned.',
16799
+ },
16681
16800
  ageAssuranceState: {
16682
16801
  type: 'string',
16683
16802
  description:
@@ -34,6 +34,8 @@ export interface ProfileViewBasic {
34
34
  createdAt?: string
35
35
  verification?: VerificationState
36
36
  status?: StatusView
37
+ /** Debug information for internal development */
38
+ debug?: { [_ in string]: unknown }
37
39
  }
38
40
 
39
41
  const hashProfileViewBasic = 'profileViewBasic'
@@ -61,6 +63,8 @@ export interface ProfileView {
61
63
  labels?: ComAtprotoLabelDefs.Label[]
62
64
  verification?: VerificationState
63
65
  status?: StatusView
66
+ /** Debug information for internal development */
67
+ debug?: { [_ in string]: unknown }
64
68
  }
65
69
 
66
70
  const hashProfileView = 'profileView'
@@ -95,6 +99,8 @@ export interface ProfileViewDetailed {
95
99
  pinnedPost?: ComAtprotoRepoStrongRef.Main
96
100
  verification?: VerificationState
97
101
  status?: StatusView
102
+ /** Debug information for internal development */
103
+ debug?: { [_ in string]: unknown }
98
104
  }
99
105
 
100
106
  const hashProfileViewDetailed = 'profileViewDetailed'
@@ -45,6 +45,8 @@ export interface PostView {
45
45
  viewer?: ViewerState
46
46
  labels?: ComAtprotoLabelDefs.Label[]
47
47
  threadgate?: ThreadgateView
48
+ /** Debug information for internal development */
49
+ debug?: { [_ in string]: unknown }
48
50
  }
49
51
 
50
52
  const hashPostView = 'postView'