@atproto/pds 0.3.9 → 0.3.10

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.
@@ -124,6 +124,7 @@ export declare const COM_ATPROTO_MODERATION: {
124
124
  DefsReasonSexual: string;
125
125
  DefsReasonRude: string;
126
126
  DefsReasonOther: string;
127
+ DefsReasonAppeal: string;
127
128
  };
128
129
  export declare const APP_BSKY_GRAPH: {
129
130
  DefsModlist: string;
@@ -177,9 +177,18 @@ export declare const schemaDict: {
177
177
  type: string;
178
178
  format: string;
179
179
  };
180
+ lastAppealedAt: {
181
+ type: string;
182
+ format: string;
183
+ description: string;
184
+ };
180
185
  takendown: {
181
186
  type: string;
182
187
  };
188
+ appealed: {
189
+ type: string;
190
+ description: string;
191
+ };
183
192
  suspendUntil: {
184
193
  type: string;
185
194
  format: string;
@@ -606,6 +615,16 @@ export declare const schemaDict: {
606
615
  };
607
616
  };
608
617
  };
618
+ modEventResolveAppeal: {
619
+ type: string;
620
+ description: string;
621
+ properties: {
622
+ comment: {
623
+ type: string;
624
+ description: string;
625
+ };
626
+ };
627
+ };
609
628
  modEventComment: {
610
629
  type: string;
611
630
  description: string;
@@ -705,6 +724,10 @@ export declare const schemaDict: {
705
724
  type: string;
706
725
  description: string;
707
726
  };
727
+ comment: {
728
+ type: string;
729
+ description: string;
730
+ };
708
731
  };
709
732
  };
710
733
  };
@@ -1214,6 +1237,10 @@ export declare const schemaDict: {
1214
1237
  type: string;
1215
1238
  description: string;
1216
1239
  };
1240
+ appealed: {
1241
+ type: string;
1242
+ description: string;
1243
+ };
1217
1244
  limit: {
1218
1245
  type: string;
1219
1246
  minimum: number;
@@ -1324,6 +1351,10 @@ export declare const schemaDict: {
1324
1351
  type: string;
1325
1352
  format: string;
1326
1353
  };
1354
+ comment: {
1355
+ type: string;
1356
+ description: string;
1357
+ };
1327
1358
  };
1328
1359
  };
1329
1360
  };
@@ -1777,6 +1808,10 @@ export declare const schemaDict: {
1777
1808
  type: string;
1778
1809
  description: string;
1779
1810
  };
1811
+ reasonAppeal: {
1812
+ type: string;
1813
+ description: string;
1814
+ };
1780
1815
  };
1781
1816
  };
1782
1817
  ComAtprotoRepoApplyWrites: {
@@ -31,7 +31,7 @@ export declare function isModEventView(v: unknown): v is ModEventView;
31
31
  export declare function validateModEventView(v: unknown): ValidationResult;
32
32
  export interface ModEventViewDetail {
33
33
  id: number;
34
- event: ModEventTakedown | ModEventReverseTakedown | ModEventComment | ModEventReport | ModEventLabel | ModEventAcknowledge | ModEventEscalate | ModEventMute | {
34
+ event: ModEventTakedown | ModEventReverseTakedown | ModEventComment | ModEventReport | ModEventLabel | ModEventAcknowledge | ModEventEscalate | ModEventMute | ModEventResolveAppeal | {
35
35
  $type: string;
36
36
  [k: string]: unknown;
37
37
  };
@@ -78,7 +78,9 @@ export interface SubjectStatusView {
78
78
  lastReviewedBy?: string;
79
79
  lastReviewedAt?: string;
80
80
  lastReportedAt?: string;
81
+ lastAppealedAt?: string;
81
82
  takendown?: boolean;
83
+ appealed?: boolean;
82
84
  suspendUntil?: string;
83
85
  [k: string]: unknown;
84
86
  }
@@ -254,6 +256,12 @@ export interface ModEventReverseTakedown {
254
256
  }
255
257
  export declare function isModEventReverseTakedown(v: unknown): v is ModEventReverseTakedown;
256
258
  export declare function validateModEventReverseTakedown(v: unknown): ValidationResult;
259
+ export interface ModEventResolveAppeal {
260
+ comment?: string;
261
+ [k: string]: unknown;
262
+ }
263
+ export declare function isModEventResolveAppeal(v: unknown): v is ModEventResolveAppeal;
264
+ export declare function validateModEventResolveAppeal(v: unknown): ValidationResult;
257
265
  export interface ModEventComment {
258
266
  comment: string;
259
267
  sticky?: boolean;
@@ -303,6 +311,7 @@ export declare function isModEventUnmute(v: unknown): v is ModEventUnmute;
303
311
  export declare function validateModEventUnmute(v: unknown): ValidationResult;
304
312
  export interface ModEventEmail {
305
313
  subjectLine: string;
314
+ comment?: string;
306
315
  [k: string]: unknown;
307
316
  }
308
317
  export declare function isModEventEmail(v: unknown): v is ModEventEmail;
@@ -15,6 +15,7 @@ export interface QueryParams {
15
15
  sortField: 'lastReviewedAt' | 'lastReportedAt';
16
16
  sortDirection: 'asc' | 'desc';
17
17
  takendown?: boolean;
18
+ appealed?: boolean;
18
19
  limit: number;
19
20
  cursor?: string;
20
21
  }
@@ -7,6 +7,7 @@ export interface InputSchema {
7
7
  content: string;
8
8
  subject?: string;
9
9
  senderDid: string;
10
+ comment?: string;
10
11
  [k: string]: unknown;
11
12
  }
12
13
  export interface OutputSchema {
@@ -1,7 +1,8 @@
1
- export declare type ReasonType = 'com.atproto.moderation.defs#reasonSpam' | 'com.atproto.moderation.defs#reasonViolation' | 'com.atproto.moderation.defs#reasonMisleading' | 'com.atproto.moderation.defs#reasonSexual' | 'com.atproto.moderation.defs#reasonRude' | 'com.atproto.moderation.defs#reasonOther' | (string & {});
1
+ export declare type ReasonType = 'com.atproto.moderation.defs#reasonSpam' | 'com.atproto.moderation.defs#reasonViolation' | 'com.atproto.moderation.defs#reasonMisleading' | 'com.atproto.moderation.defs#reasonSexual' | 'com.atproto.moderation.defs#reasonRude' | 'com.atproto.moderation.defs#reasonOther' | 'com.atproto.moderation.defs#reasonAppeal' | (string & {});
2
2
  export declare const REASONSPAM = "com.atproto.moderation.defs#reasonSpam";
3
3
  export declare const REASONVIOLATION = "com.atproto.moderation.defs#reasonViolation";
4
4
  export declare const REASONMISLEADING = "com.atproto.moderation.defs#reasonMisleading";
5
5
  export declare const REASONSEXUAL = "com.atproto.moderation.defs#reasonSexual";
6
6
  export declare const REASONRUDE = "com.atproto.moderation.defs#reasonRude";
7
7
  export declare const REASONOTHER = "com.atproto.moderation.defs#reasonOther";
8
+ export declare const REASONAPPEAL = "com.atproto.moderation.defs#reasonAppeal";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/pds",
3
- "version": "0.3.9",
3
+ "version": "0.3.10",
4
4
  "license": "MIT",
5
5
  "description": "Reference implementation of atproto Personal Data Server (PDS)",
6
6
  "keywords": [
@@ -16,7 +16,7 @@
16
16
  "main": "dist/index.js",
17
17
  "bin": "dist/bin.js",
18
18
  "dependencies": {
19
- "@did-plc/lib": "^0.0.1",
19
+ "@did-plc/lib": "^0.0.4",
20
20
  "better-sqlite3": "^7.6.2",
21
21
  "bytes": "^3.1.2",
22
22
  "compression": "^1.7.4",
@@ -44,7 +44,7 @@
44
44
  "typed-emitter": "^2.1.0",
45
45
  "uint8arrays": "3.0.0",
46
46
  "zod": "^3.21.4",
47
- "@atproto/api": "^0.7.4",
47
+ "@atproto/api": "^0.8.0",
48
48
  "@atproto/aws": "^0.1.6",
49
49
  "@atproto/common": "^0.3.3",
50
50
  "@atproto/crypto": "^0.3.0",
@@ -68,9 +68,9 @@
68
68
  "axios": "^0.27.2",
69
69
  "get-port": "^6.1.2",
70
70
  "ws": "^8.12.0",
71
- "@atproto/api": "^0.7.4",
72
- "@atproto/bsky": "^0.0.21",
73
- "@atproto/dev-env": "^0.2.21",
71
+ "@atproto/api": "^0.8.0",
72
+ "@atproto/bsky": "^0.0.22",
73
+ "@atproto/dev-env": "^0.2.22",
74
74
  "@atproto/lex-cli": "^0.2.5"
75
75
  },
76
76
  "scripts": {
@@ -11,7 +11,7 @@ export default function (server: Server, ctx: AppContext) {
11
11
  'Account invites are managed by the entryway service',
12
12
  )
13
13
  }
14
- if (!auth.credentials.admin) {
14
+ if (!auth.credentials.moderator) {
15
15
  throw new AuthRequiredError('Insufficient privileges')
16
16
  }
17
17
  const { account } = input.body
@@ -11,7 +11,7 @@ export default function (server: Server, ctx: AppContext) {
11
11
  'Account invites are managed by the entryway service',
12
12
  )
13
13
  }
14
- if (!auth.credentials.admin) {
14
+ if (!auth.credentials.moderator) {
15
15
  throw new AuthRequiredError('Insufficient privileges')
16
16
  }
17
17
  const { codes = [], accounts = [] } = input.body
@@ -11,7 +11,7 @@ export default function (server: Server, ctx: AppContext) {
11
11
  'Account invites are managed by the entryway service',
12
12
  )
13
13
  }
14
- if (!auth.credentials.admin) {
14
+ if (!auth.credentials.moderator) {
15
15
  throw new AuthRequiredError('Insufficient privileges')
16
16
  }
17
17
  const { account } = input.body
@@ -16,6 +16,7 @@ export default function (server: Server, ctx: AppContext) {
16
16
  recipientDid,
17
17
  senderDid,
18
18
  subject = 'Message from Bluesky moderator',
19
+ comment,
19
20
  } = input.body
20
21
  const account = await ctx.accountManager.getAccount(recipientDid)
21
22
  if (!account) {
@@ -44,6 +45,7 @@ export default function (server: Server, ctx: AppContext) {
44
45
  event: {
45
46
  $type: 'com.atproto.admin.defs#modEventEmail',
46
47
  subjectLine: subject,
48
+ comment,
47
49
  },
48
50
  subject: {
49
51
  $type: 'com.atproto.admin.defs#repoRef',
@@ -10,6 +10,7 @@ import {
10
10
  REASONRUDE,
11
11
  REASONSEXUAL,
12
12
  REASONVIOLATION,
13
+ REASONAPPEAL,
13
14
  } from '../../../../lexicon/types/com/atproto/moderation/defs'
14
15
  import { parseCidParam } from '../../../../util/params'
15
16
 
@@ -49,4 +50,5 @@ const reasonTypes = new Set([
49
50
  REASONRUDE,
50
51
  REASONSEXUAL,
51
52
  REASONVIOLATION,
53
+ REASONAPPEAL,
52
54
  ])
@@ -2,12 +2,12 @@ import { DidDocument, MINUTE, check } from '@atproto/common'
2
2
  import { AtprotoData, ensureAtpDocument } from '@atproto/identity'
3
3
  import { InvalidRequestError } from '@atproto/xrpc-server'
4
4
  import { ExportableKeypair, Keypair, Secp256k1Keypair } from '@atproto/crypto'
5
+ import * as plc from '@did-plc/lib'
5
6
  import disposable from 'disposable-email'
6
7
  import {
7
8
  baseNormalizeAndValidate,
8
9
  normalizeAndValidateHandle,
9
10
  } from '../../../../handle'
10
- import * as plc from '@did-plc/lib'
11
11
  import { Server } from '../../../../lexicon'
12
12
  import { InputSchema as CreateAccountInput } from '../../../../lexicon/types/com/atproto/server/createAccount'
13
13
  import AppContext from '../../../../context'
@@ -101,7 +101,12 @@ const validateInputsForEntrywayPds = async (
101
101
  'IncompatibleDidDoc',
102
102
  )
103
103
  }
104
- await plc.assureValidOp(plcOp)
104
+ try {
105
+ await plc.assureValidOp(plcOp)
106
+ await plc.assureValidSig([plcRotationKey], plcOp)
107
+ } catch (err) {
108
+ throw new InvalidRequestError('invalid plc operation', 'IncompatibleDidDoc')
109
+ }
105
110
  const doc = plc.formatDidDoc({ did, ...plcOp })
106
111
  const data = ensureAtpDocument(doc)
107
112
 
@@ -135,6 +135,7 @@ export const COM_ATPROTO_MODERATION = {
135
135
  DefsReasonSexual: 'com.atproto.moderation.defs#reasonSexual',
136
136
  DefsReasonRude: 'com.atproto.moderation.defs#reasonRude',
137
137
  DefsReasonOther: 'com.atproto.moderation.defs#reasonOther',
138
+ DefsReasonAppeal: 'com.atproto.moderation.defs#reasonAppeal',
138
139
  }
139
140
  export const APP_BSKY_GRAPH = {
140
141
  DefsModlist: 'app.bsky.graph.defs#modlist',
@@ -102,6 +102,7 @@ export const schemaDict = {
102
102
  'lex:com.atproto.admin.defs#modEventAcknowledge',
103
103
  'lex:com.atproto.admin.defs#modEventEscalate',
104
104
  'lex:com.atproto.admin.defs#modEventMute',
105
+ 'lex:com.atproto.admin.defs#modEventResolveAppeal',
105
106
  ],
106
107
  },
107
108
  subject: {
@@ -237,9 +238,20 @@ export const schemaDict = {
237
238
  type: 'string',
238
239
  format: 'datetime',
239
240
  },
241
+ lastAppealedAt: {
242
+ type: 'string',
243
+ format: 'datetime',
244
+ description:
245
+ 'Timestamp referencing when the author of the subject appealed a moderation action',
246
+ },
240
247
  takendown: {
241
248
  type: 'boolean',
242
249
  },
250
+ appealed: {
251
+ type: 'boolean',
252
+ description:
253
+ 'True indicates that the a previously taken moderator action was appealed against, by the author of the content. False indicates last appeal was resolved by moderators.',
254
+ },
243
255
  suspendUntil: {
244
256
  type: 'string',
245
257
  format: 'datetime',
@@ -717,6 +729,16 @@ export const schemaDict = {
717
729
  },
718
730
  },
719
731
  },
732
+ modEventResolveAppeal: {
733
+ type: 'object',
734
+ description: 'Resolve appeal on a subject',
735
+ properties: {
736
+ comment: {
737
+ type: 'string',
738
+ description: 'Describe resolution.',
739
+ },
740
+ },
741
+ },
720
742
  modEventComment: {
721
743
  type: 'object',
722
744
  description: 'Add a comment to a subject',
@@ -816,6 +838,10 @@ export const schemaDict = {
816
838
  type: 'string',
817
839
  description: 'The subject line of the email sent to the user.',
818
840
  },
841
+ comment: {
842
+ type: 'string',
843
+ description: 'Additional comment about the outgoing comm.',
844
+ },
819
845
  },
820
846
  },
821
847
  },
@@ -1357,6 +1383,10 @@ export const schemaDict = {
1357
1383
  type: 'boolean',
1358
1384
  description: 'Get subjects that were taken down',
1359
1385
  },
1386
+ appealed: {
1387
+ type: 'boolean',
1388
+ description: 'Get subjects in unresolved appealed status',
1389
+ },
1360
1390
  limit: {
1361
1391
  type: 'integer',
1362
1392
  minimum: 1,
@@ -1467,6 +1497,11 @@ export const schemaDict = {
1467
1497
  type: 'string',
1468
1498
  format: 'did',
1469
1499
  },
1500
+ comment: {
1501
+ type: 'string',
1502
+ description:
1503
+ "Additional comment by the sender that won't be used in the email itself but helpful to provide more context for moderators/reviewers",
1504
+ },
1470
1505
  },
1471
1506
  },
1472
1507
  },
@@ -1937,6 +1972,7 @@ export const schemaDict = {
1937
1972
  'com.atproto.moderation.defs#reasonSexual',
1938
1973
  'com.atproto.moderation.defs#reasonRude',
1939
1974
  'com.atproto.moderation.defs#reasonOther',
1975
+ 'com.atproto.moderation.defs#reasonAppeal',
1940
1976
  ],
1941
1977
  },
1942
1978
  reasonSpam: {
@@ -1964,6 +2000,10 @@ export const schemaDict = {
1964
2000
  type: 'token',
1965
2001
  description: 'Other: reports not falling under another report category',
1966
2002
  },
2003
+ reasonAppeal: {
2004
+ type: 'token',
2005
+ description: 'Appeal: appeal a previously taken moderation action',
2006
+ },
1967
2007
  },
1968
2008
  },
1969
2009
  ComAtprotoRepoApplyWrites: {
@@ -76,6 +76,7 @@ export interface ModEventViewDetail {
76
76
  | ModEventAcknowledge
77
77
  | ModEventEscalate
78
78
  | ModEventMute
79
+ | ModEventResolveAppeal
79
80
  | { $type: string; [k: string]: unknown }
80
81
  subject:
81
82
  | RepoView
@@ -147,7 +148,11 @@ export interface SubjectStatusView {
147
148
  lastReviewedBy?: string
148
149
  lastReviewedAt?: string
149
150
  lastReportedAt?: string
151
+ /** Timestamp referencing when the author of the subject appealed a moderation action */
152
+ lastAppealedAt?: string
150
153
  takendown?: boolean
154
+ /** True indicates that the a previously taken moderator action was appealed against, by the author of the content. False indicates last appeal was resolved by moderators. */
155
+ appealed?: boolean
151
156
  suspendUntil?: string
152
157
  [k: string]: unknown
153
158
  }
@@ -538,6 +543,27 @@ export function validateModEventReverseTakedown(v: unknown): ValidationResult {
538
543
  return lexicons.validate('com.atproto.admin.defs#modEventReverseTakedown', v)
539
544
  }
540
545
 
546
+ /** Resolve appeal on a subject */
547
+ export interface ModEventResolveAppeal {
548
+ /** Describe resolution. */
549
+ comment?: string
550
+ [k: string]: unknown
551
+ }
552
+
553
+ export function isModEventResolveAppeal(
554
+ v: unknown,
555
+ ): v is ModEventResolveAppeal {
556
+ return (
557
+ isObj(v) &&
558
+ hasProp(v, '$type') &&
559
+ v.$type === 'com.atproto.admin.defs#modEventResolveAppeal'
560
+ )
561
+ }
562
+
563
+ export function validateModEventResolveAppeal(v: unknown): ValidationResult {
564
+ return lexicons.validate('com.atproto.admin.defs#modEventResolveAppeal', v)
565
+ }
566
+
541
567
  /** Add a comment to a subject */
542
568
  export interface ModEventComment {
543
569
  comment: string
@@ -674,6 +700,8 @@ export function validateModEventUnmute(v: unknown): ValidationResult {
674
700
  export interface ModEventEmail {
675
701
  /** The subject line of the email sent to the user. */
676
702
  subjectLine: string
703
+ /** Additional comment about the outgoing comm. */
704
+ comment?: string
677
705
  [k: string]: unknown
678
706
  }
679
707
 
@@ -32,6 +32,8 @@ export interface QueryParams {
32
32
  sortDirection: 'asc' | 'desc'
33
33
  /** Get subjects that were taken down */
34
34
  takendown?: boolean
35
+ /** Get subjects in unresolved appealed status */
36
+ appealed?: boolean
35
37
  limit: number
36
38
  cursor?: string
37
39
  }
@@ -15,6 +15,8 @@ export interface InputSchema {
15
15
  content: string
16
16
  subject?: string
17
17
  senderDid: string
18
+ /** Additional comment by the sender that won't be used in the email itself but helpful to provide more context for moderators/reviewers */
19
+ comment?: string
18
20
  [k: string]: unknown
19
21
  }
20
22
 
@@ -13,6 +13,7 @@ export type ReasonType =
13
13
  | 'com.atproto.moderation.defs#reasonSexual'
14
14
  | 'com.atproto.moderation.defs#reasonRude'
15
15
  | 'com.atproto.moderation.defs#reasonOther'
16
+ | 'com.atproto.moderation.defs#reasonAppeal'
16
17
  | (string & {})
17
18
 
18
19
  /** Spam: frequent unwanted promotion, replies, mentions */
@@ -27,3 +28,5 @@ export const REASONSEXUAL = 'com.atproto.moderation.defs#reasonSexual'
27
28
  export const REASONRUDE = 'com.atproto.moderation.defs#reasonRude'
28
29
  /** Other: reports not falling under another report category */
29
30
  export const REASONOTHER = 'com.atproto.moderation.defs#reasonOther'
31
+ /** Appeal: appeal a previously taken moderation action */
32
+ export const REASONAPPEAL = 'com.atproto.moderation.defs#reasonAppeal'
@@ -1,5 +1,6 @@
1
1
  import * as os from 'node:os'
2
2
  import * as path from 'node:path'
3
+ import * as plcLib from '@did-plc/lib'
3
4
  import AtpAgent from '@atproto/api'
4
5
  import { Secp256k1Keypair, randomStr } from '@atproto/crypto'
5
6
  import { SeedClient, TestPds, TestPlc, mockResolvers } from '@atproto/dev-env'
@@ -131,6 +132,28 @@ describe('entryway', () => {
131
132
  expect(accountFromPds?.handle).toEqual('alice3.test')
132
133
  expect(accountFromEntryway?.handle).toEqual('alice3.test')
133
134
  })
135
+
136
+ it('does not allow bringing own op to account creation.', async () => {
137
+ const {
138
+ data: { signingKey },
139
+ } = await pdsAgent.api.com.atproto.server.reserveSigningKey({})
140
+ const rotationKey = await Secp256k1Keypair.create()
141
+ const plcCreate = await plcLib.createOp({
142
+ signingKey,
143
+ rotationKeys: [rotationKey.did(), entryway.ctx.plcRotationKey.did()],
144
+ handle: 'weirdalice.test',
145
+ pds: pds.ctx.cfg.service.publicUrl,
146
+ signer: rotationKey,
147
+ })
148
+ const tryCreateAccount = pdsAgent.api.com.atproto.server.createAccount(
149
+ { did: plcCreate.did, plcOp: plcCreate.op, handle: 'weirdalice.test' },
150
+ {
151
+ headers: SeedClient.getHeaders(accessToken),
152
+ encoding: 'application/json',
153
+ },
154
+ )
155
+ await expect(tryCreateAccount).rejects.toThrow('invalid plc operation')
156
+ })
134
157
  })
135
158
 
136
159
  const createEntryway = async (
@@ -177,13 +177,13 @@ describe('pds admin invite views', () => {
177
177
  expect(aliceView.data.invites?.length).toBe(6)
178
178
  })
179
179
 
180
- it('does not allow non-admin moderators to disable invites.', async () => {
180
+ it('does not allow triage moderators to disable invites.', async () => {
181
181
  const attemptDisableInvites =
182
182
  agent.api.com.atproto.admin.disableInviteCodes(
183
183
  { codes: ['x'], accounts: [alice] },
184
184
  {
185
185
  encoding: 'application/json',
186
- headers: network.pds.adminAuthHeaders('moderator'),
186
+ headers: network.pds.adminAuthHeaders('triage'),
187
187
  },
188
188
  )
189
189
  await expect(attemptDisableInvites).rejects.toThrow(
@@ -255,12 +255,12 @@ describe('pds admin invite views', () => {
255
255
  expect(res.every((row) => row.disabled === 1))
256
256
  })
257
257
 
258
- it('does not allow non-admin moderations to disable account invites', async () => {
258
+ it('does not allow triage moderators to disable account invites', async () => {
259
259
  const attempt = agent.api.com.atproto.admin.disableAccountInvites(
260
260
  { account: alice },
261
261
  {
262
262
  encoding: 'application/json',
263
- headers: network.pds.adminAuthHeaders('moderator'),
263
+ headers: network.pds.adminAuthHeaders('triage'),
264
264
  },
265
265
  )
266
266
  await expect(attempt).rejects.toThrow('Insufficient privileges')
@@ -285,12 +285,12 @@ describe('pds admin invite views', () => {
285
285
  expect(invRes.data.codes.length).toBeGreaterThan(0)
286
286
  })
287
287
 
288
- it('does not allow non-admin moderations to enable account invites', async () => {
288
+ it('does not allow triage moderators to enable account invites', async () => {
289
289
  const attempt = agent.api.com.atproto.admin.enableAccountInvites(
290
290
  { account: alice },
291
291
  {
292
292
  encoding: 'application/json',
293
- headers: network.pds.adminAuthHeaders('moderator'),
293
+ headers: network.pds.adminAuthHeaders('triage'),
294
294
  },
295
295
  )
296
296
  await expect(attempt).rejects.toThrow('Insufficient privileges')