@atproto/pds 0.4.60 → 0.4.61

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/account-manager/helpers/account.d.ts +1 -0
  3. package/dist/account-manager/helpers/account.d.ts.map +1 -1
  4. package/dist/account-manager/helpers/account.js +15 -1
  5. package/dist/account-manager/helpers/account.js.map +1 -1
  6. package/dist/account-manager/helpers/invite.d.ts +1 -1
  7. package/dist/account-manager/helpers/invite.d.ts.map +1 -1
  8. package/dist/account-manager/helpers/invite.js +20 -9
  9. package/dist/account-manager/helpers/invite.js.map +1 -1
  10. package/dist/account-manager/index.d.ts +2 -0
  11. package/dist/account-manager/index.d.ts.map +1 -1
  12. package/dist/account-manager/index.js +8 -1
  13. package/dist/account-manager/index.js.map +1 -1
  14. package/dist/api/com/atproto/admin/getAccountInfo.d.ts.map +1 -1
  15. package/dist/api/com/atproto/admin/getAccountInfo.js +6 -14
  16. package/dist/api/com/atproto/admin/getAccountInfo.js.map +1 -1
  17. package/dist/api/com/atproto/admin/getAccountInfos.d.ts +4 -0
  18. package/dist/api/com/atproto/admin/getAccountInfos.d.ts.map +1 -0
  19. package/dist/api/com/atproto/admin/getAccountInfos.js +32 -0
  20. package/dist/api/com/atproto/admin/getAccountInfos.js.map +1 -0
  21. package/dist/api/com/atproto/admin/index.d.ts.map +1 -1
  22. package/dist/api/com/atproto/admin/index.js +2 -0
  23. package/dist/api/com/atproto/admin/index.js.map +1 -1
  24. package/dist/api/com/atproto/admin/util.d.ts +17 -0
  25. package/dist/api/com/atproto/admin/util.d.ts.map +1 -1
  26. package/dist/api/com/atproto/admin/util.js +27 -1
  27. package/dist/api/com/atproto/admin/util.js.map +1 -1
  28. package/dist/api/com/atproto/repo/getRecord.d.ts.map +1 -1
  29. package/dist/api/com/atproto/repo/getRecord.js +1 -1
  30. package/dist/api/com/atproto/repo/getRecord.js.map +1 -1
  31. package/dist/config/config.d.ts +8 -0
  32. package/dist/config/config.d.ts.map +1 -1
  33. package/dist/config/config.js +1 -0
  34. package/dist/config/config.js.map +1 -1
  35. package/dist/config/env.d.ts +1 -0
  36. package/dist/config/env.d.ts.map +1 -1
  37. package/dist/config/env.js +1 -0
  38. package/dist/config/env.js.map +1 -1
  39. package/dist/lexicon/index.d.ts +4 -0
  40. package/dist/lexicon/index.d.ts.map +1 -1
  41. package/dist/lexicon/index.js +8 -0
  42. package/dist/lexicon/index.js.map +1 -1
  43. package/dist/lexicon/lexicons.d.ts +85 -0
  44. package/dist/lexicon/lexicons.d.ts.map +1 -1
  45. package/dist/lexicon/lexicons.js +93 -0
  46. package/dist/lexicon/lexicons.js.map +1 -1
  47. package/dist/lexicon/types/com/atproto/repo/getRecord.d.ts +1 -0
  48. package/dist/lexicon/types/com/atproto/repo/getRecord.d.ts.map +1 -1
  49. package/dist/lexicon/types/tools/ozone/moderation/getRecords.d.ts +39 -0
  50. package/dist/lexicon/types/tools/ozone/moderation/getRecords.d.ts.map +1 -0
  51. package/dist/lexicon/types/tools/ozone/moderation/getRecords.js +3 -0
  52. package/dist/lexicon/types/tools/ozone/moderation/getRecords.js.map +1 -0
  53. package/dist/lexicon/types/tools/ozone/moderation/getRepos.d.ts +39 -0
  54. package/dist/lexicon/types/tools/ozone/moderation/getRepos.d.ts.map +1 -0
  55. package/dist/lexicon/types/tools/ozone/moderation/getRepos.js +3 -0
  56. package/dist/lexicon/types/tools/ozone/moderation/getRepos.js.map +1 -0
  57. package/dist/mailer/templates/confirm-email.js +1 -1
  58. package/dist/mailer/templates/confirm-email.js.map +1 -1
  59. package/dist/mailer/templates/delete-account.js +1 -1
  60. package/dist/mailer/templates/delete-account.js.map +1 -1
  61. package/dist/mailer/templates/plc-operation.js +1 -1
  62. package/dist/mailer/templates/plc-operation.js.map +1 -1
  63. package/dist/mailer/templates/reset-password.js +1 -1
  64. package/dist/mailer/templates/reset-password.js.map +1 -1
  65. package/dist/mailer/templates/update-email.js +1 -1
  66. package/dist/mailer/templates/update-email.js.map +1 -1
  67. package/dist/pipethrough.d.ts +1 -1
  68. package/dist/pipethrough.d.ts.map +1 -1
  69. package/dist/pipethrough.js +105 -73
  70. package/dist/pipethrough.js.map +1 -1
  71. package/package.json +11 -11
  72. package/src/account-manager/helpers/account.ts +22 -0
  73. package/src/account-manager/helpers/invite.ts +19 -9
  74. package/src/account-manager/index.ts +13 -1
  75. package/src/api/com/atproto/admin/getAccountInfo.ts +6 -13
  76. package/src/api/com/atproto/admin/getAccountInfos.ts +33 -0
  77. package/src/api/com/atproto/admin/index.ts +2 -0
  78. package/src/api/com/atproto/admin/util.ts +38 -0
  79. package/src/api/com/atproto/repo/getRecord.ts +4 -1
  80. package/src/config/config.ts +10 -0
  81. package/src/config/env.ts +2 -0
  82. package/src/lexicon/index.ts +24 -0
  83. package/src/lexicon/lexicons.ts +93 -0
  84. package/src/lexicon/types/com/atproto/repo/getRecord.ts +1 -0
  85. package/src/lexicon/types/tools/ozone/moderation/getRecords.ts +50 -0
  86. package/src/lexicon/types/tools/ozone/moderation/getRepos.ts +50 -0
  87. package/src/mailer/templates/confirm-email.hbs +1 -1
  88. package/src/mailer/templates/delete-account.hbs +1 -1
  89. package/src/mailer/templates/plc-operation.hbs +1 -1
  90. package/src/mailer/templates/reset-password.hbs +1 -1
  91. package/src/mailer/templates/update-email.hbs +1 -1
  92. package/src/pipethrough.ts +131 -92
  93. package/tests/proxied/read-after-write.test.ts +77 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/pds",
3
- "version": "0.4.60",
3
+ "version": "0.4.61",
4
4
  "license": "MIT",
5
5
  "description": "Reference implementation of atproto Personal Data Server (PDS)",
6
6
  "keywords": [
@@ -44,18 +44,18 @@
44
44
  "uint8arrays": "3.0.0",
45
45
  "undici": "^6.19.8",
46
46
  "zod": "^3.23.8",
47
- "@atproto/api": "^0.13.8",
48
- "@atproto/aws": "^0.2.6",
49
- "@atproto/common": "^0.4.3",
47
+ "@atproto-labs/fetch-node": "0.1.1",
48
+ "@atproto/api": "^0.13.9",
49
+ "@atproto/aws": "^0.2.7",
50
+ "@atproto/common": "^0.4.4",
50
51
  "@atproto/crypto": "^0.4.1",
51
52
  "@atproto/identity": "^0.4.2",
52
- "@atproto-labs/fetch-node": "0.1.1",
53
53
  "@atproto/lexicon": "^0.4.2",
54
- "@atproto/oauth-provider": "^0.2.2",
55
- "@atproto/repo": "^0.5.2",
54
+ "@atproto/oauth-provider": "^0.2.3",
55
+ "@atproto/repo": "^0.5.3",
56
+ "@atproto/syntax": "^0.3.0",
56
57
  "@atproto/xrpc": "^0.6.3",
57
- "@atproto/xrpc-server": "^0.7.0",
58
- "@atproto/syntax": "^0.3.0"
58
+ "@atproto/xrpc-server": "^0.7.1"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@atproto/pds-entryway": "npm:@atproto/pds@0.3.0-entryway.3",
@@ -73,8 +73,8 @@
73
73
  "jest": "^28.1.2",
74
74
  "ts-node": "^10.8.2",
75
75
  "ws": "^8.12.0",
76
- "@atproto/api": "^0.13.8",
77
- "@atproto/bsky": "^0.0.84",
76
+ "@atproto/api": "^0.13.9",
77
+ "@atproto/bsky": "^0.0.85",
78
78
  "@atproto/lex-cli": "^0.5.1"
79
79
  },
80
80
  "scripts": {
@@ -64,6 +64,28 @@ export const getAccount = async (
64
64
  return found || null
65
65
  }
66
66
 
67
+ export const getAccounts = async (
68
+ db: AccountDb,
69
+ dids: string[],
70
+ flags?: AvailabilityFlags,
71
+ ): Promise<Map<string, ActorAccount>> => {
72
+ const results = new Map<string, ActorAccount>()
73
+
74
+ if (!dids.length) {
75
+ return results
76
+ }
77
+
78
+ const accounts = await selectAccountQB(db, flags)
79
+ .where('actor.did', 'in', dids)
80
+ .execute()
81
+
82
+ accounts.forEach((account) => {
83
+ results.set(account.did, account)
84
+ })
85
+
86
+ return results
87
+ }
88
+
67
89
  export const getAccountByEmail = async (
68
90
  db: AccountDb,
69
91
  email: string,
@@ -139,20 +139,30 @@ export const selectInviteCodesQb = (db: AccountDb) => {
139
139
  return db.db.selectFrom(builder.as('codes')).selectAll()
140
140
  }
141
141
 
142
- export const getAccountInviteCodes = async (
142
+ export const getAccountsInviteCodes = async (
143
143
  db: AccountDb,
144
- did: string,
145
- ): Promise<CodeDetail[]> => {
144
+ dids: string[],
145
+ ): Promise<Map<string, CodeDetail[]>> => {
146
+ const results = new Map<string, CodeDetail[]>()
147
+ // We don't want to pass an empty array to kysely and let's avoid running a query entirely if there is nothing to match for
148
+ if (!dids.length) return results
146
149
  const res = await selectInviteCodesQb(db)
147
- .where('forAccount', '=', did)
150
+ .where('forAccount', 'in', dids)
148
151
  .execute()
149
152
  const codes = res.map((row) => row.code)
150
153
  const uses = await getInviteCodesUses(db, codes)
151
- return res.map((row) => ({
152
- ...row,
153
- uses: uses[row.code] ?? [],
154
- disabled: row.disabled === 1,
155
- }))
154
+ res.forEach((row) => {
155
+ const existing = results.get(row.forAccount) ?? []
156
+ results.set(row.forAccount, [
157
+ ...existing,
158
+ {
159
+ ...row,
160
+ uses: uses[row.code] ?? [],
161
+ disabled: row.disabled === 1,
162
+ },
163
+ ])
164
+ })
165
+ return results
156
166
  }
157
167
 
158
168
  export const getInviteCodesUses = async (
@@ -78,6 +78,13 @@ export class AccountManager
78
78
  return account.getAccount(this.db, handleOrDid, flags)
79
79
  }
80
80
 
81
+ async getAccounts(
82
+ dids: string[],
83
+ flags?: account.AvailabilityFlags,
84
+ ): Promise<Map<string, ActorAccount>> {
85
+ return account.getAccounts(this.db, dids, flags)
86
+ }
87
+
81
88
  async getAccountByEmail(
82
89
  email: string,
83
90
  flags?: account.AvailabilityFlags,
@@ -397,7 +404,12 @@ export class AccountManager
397
404
  }
398
405
 
399
406
  async getAccountInvitesCodes(did: string) {
400
- return invite.getAccountInviteCodes(this.db, did)
407
+ const inviteCodes = await invite.getAccountsInviteCodes(this.db, [did])
408
+ return inviteCodes.get(did) ?? []
409
+ }
410
+
411
+ async getAccountsInvitesCodes(dids: string[]) {
412
+ return invite.getAccountsInviteCodes(this.db, dids)
401
413
  }
402
414
 
403
415
  async getInvitedByForAccounts(dids: string[]) {
@@ -2,6 +2,7 @@ import { Server } from '../../../../lexicon'
2
2
  import AppContext from '../../../../context'
3
3
  import { InvalidRequestError } from '@atproto/xrpc-server'
4
4
  import { INVALID_HANDLE } from '@atproto/syntax'
5
+ import { formatAccountInfo } from './util'
5
6
 
6
7
  export default function (server: Server, ctx: AppContext) {
7
8
  server.com.atproto.admin.getAccountInfo({
@@ -21,19 +22,11 @@ export default function (server: Server, ctx: AppContext) {
21
22
  const managesOwnInvites = !ctx.cfg.entryway
22
23
  return {
23
24
  encoding: 'application/json',
24
- body: {
25
- did: account.did,
26
- handle: account.handle ?? INVALID_HANDLE,
27
- email: account.email ?? undefined,
28
- indexedAt: account.createdAt,
29
- emailConfirmedAt: account.emailConfirmedAt ?? undefined,
30
- invitedBy: managesOwnInvites ? invitedBy[params.did] : undefined,
31
- invites: managesOwnInvites ? invites : undefined,
32
- invitesDisabled: managesOwnInvites
33
- ? account.invitesDisabled === 1
34
- : undefined,
35
- deactivatedAt: account.deactivatedAt ?? undefined,
36
- },
25
+ body: formatAccountInfo(account, {
26
+ managesOwnInvites,
27
+ invitedBy,
28
+ invites,
29
+ }),
37
30
  }
38
31
  },
39
32
  })
@@ -0,0 +1,33 @@
1
+ import { Server } from '../../../../lexicon'
2
+ import AppContext from '../../../../context'
3
+ import { formatAccountInfo } from './util'
4
+
5
+ export default function (server: Server, ctx: AppContext) {
6
+ server.com.atproto.admin.getAccountInfos({
7
+ auth: ctx.authVerifier.moderator,
8
+ handler: async ({ params }) => {
9
+ const [accounts, invites, invitedBy] = await Promise.all([
10
+ ctx.accountManager.getAccounts(params.dids, {
11
+ includeDeactivated: true,
12
+ includeTakenDown: true,
13
+ }),
14
+ ctx.accountManager.getAccountsInvitesCodes(params.dids),
15
+ ctx.accountManager.getInvitedByForAccounts(params.dids),
16
+ ])
17
+
18
+ const managesOwnInvites = !ctx.cfg.entryway
19
+ const infos = Array.from(accounts.values()).map((account) => {
20
+ return formatAccountInfo(account, {
21
+ managesOwnInvites,
22
+ invitedBy,
23
+ invites,
24
+ })
25
+ })
26
+
27
+ return {
28
+ encoding: 'application/json',
29
+ body: { infos },
30
+ }
31
+ },
32
+ })
33
+ }
@@ -12,11 +12,13 @@ import updateAccountEmail from './updateAccountEmail'
12
12
  import updateAccountPassword from './updateAccountPassword'
13
13
  import sendEmail from './sendEmail'
14
14
  import deleteAccount from './deleteAccount'
15
+ import getAccountInfos from './getAccountInfos'
15
16
 
16
17
  export default function (server: Server, ctx: AppContext) {
17
18
  updateSubjectStatus(server, ctx)
18
19
  getSubjectStatus(server, ctx)
19
20
  getAccountInfo(server, ctx)
21
+ getAccountInfos(server, ctx)
20
22
  enableAccountInvites(server, ctx)
21
23
  disableAccountInvites(server, ctx)
22
24
  disableInviteCodes(server, ctx)
@@ -1,4 +1,7 @@
1
1
  import express from 'express'
2
+ import { ActorAccount } from '../../../../account-manager/helpers/account'
3
+ import { INVALID_HANDLE } from '@atproto/syntax'
4
+ import { CodeDetail } from '../../../../account-manager/helpers/invite'
2
5
 
3
6
  // Output designed to passed as second arg to AtpAgent methods.
4
7
  // The encoding field here is a quirk of the AtpAgent.
@@ -22,3 +25,38 @@ export function authPassthru(req: express.Request, withEncoding?: boolean) {
22
25
  }
23
26
  }
24
27
  }
28
+
29
+ export function formatAccountInfo(
30
+ account: ActorAccount,
31
+ {
32
+ managesOwnInvites,
33
+ invitedBy,
34
+ invites,
35
+ }: {
36
+ managesOwnInvites: boolean
37
+ invites: Map<string, CodeDetail[]> | CodeDetail[]
38
+ invitedBy: Record<string, CodeDetail>
39
+ },
40
+ ) {
41
+ let invitesResults: CodeDetail[] | undefined
42
+ if (managesOwnInvites) {
43
+ if (Array.isArray(invites)) {
44
+ invitesResults = invites
45
+ } else {
46
+ invitesResults = invites.get(account.did) || []
47
+ }
48
+ }
49
+ return {
50
+ did: account.did,
51
+ handle: account.handle ?? INVALID_HANDLE,
52
+ email: account.email ?? undefined,
53
+ indexedAt: account.createdAt,
54
+ emailConfirmedAt: account.emailConfirmedAt ?? undefined,
55
+ invitedBy: managesOwnInvites ? invitedBy[account.did] : undefined,
56
+ invites: invitesResults,
57
+ invitesDisabled: managesOwnInvites
58
+ ? account.invitesDisabled === 1
59
+ : undefined,
60
+ deactivatedAt: account.deactivatedAt ?? undefined,
61
+ }
62
+ }
@@ -16,7 +16,10 @@ export default function (server: Server, ctx: AppContext) {
16
16
  store.record.getRecord(uri, cid ?? null),
17
17
  )
18
18
  if (!record || record.takedownRef !== null) {
19
- throw new InvalidRequestError(`Could not locate record: ${uri}`)
19
+ throw new InvalidRequestError(
20
+ `Could not locate record: ${uri}`,
21
+ 'RecordNotFound',
22
+ )
20
23
  }
21
24
  return {
22
25
  encoding: 'application/json',
@@ -246,6 +246,7 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => {
246
246
  headersTimeout: env.proxyHeadersTimeout ?? 10e3,
247
247
  bodyTimeout: env.proxyBodyTimeout ?? 30e3,
248
248
  maxResponseSize: env.proxyMaxResponseSize ?? 10 * 1024 * 1024, // 10mb
249
+ preferCompressed: env.proxyPreferCompressed ?? false,
249
250
  }
250
251
 
251
252
  const oauthCfg: ServerConfig['oauth'] = entrywayCfg
@@ -413,6 +414,15 @@ export type ProxyConfig = {
413
414
  headersTimeout: number
414
415
  bodyTimeout: number
415
416
  maxResponseSize: number
417
+
418
+ /**
419
+ * When proxying requests that might get intercepted (for read-after-write) we
420
+ * negotiate the encoding based on the client's preferences. We will however
421
+ * use or own weights in order to be able to better control if the PDS will
422
+ * need to perform content decoding. This settings allows to prefer compressed
423
+ * content over uncompressed one.
424
+ */
425
+ preferCompressed: boolean
416
426
  }
417
427
 
418
428
  export type OAuthConfig = {
package/src/config/env.ts CHANGED
@@ -128,6 +128,7 @@ export const readEnv = (): ServerEnvironment => {
128
128
  proxyHeadersTimeout: envInt('PDS_PROXY_HEADERS_TIMEOUT'),
129
129
  proxyBodyTimeout: envInt('PDS_PROXY_BODY_TIMEOUT'),
130
130
  proxyMaxResponseSize: envInt('PDS_PROXY_MAX_RESPONSE_SIZE'),
131
+ proxyPreferCompressed: envBool('PDS_PROXY_PREFER_COMPRESSED'),
131
132
  }
132
133
  }
133
134
 
@@ -253,4 +254,5 @@ export type ServerEnvironment = {
253
254
  proxyHeadersTimeout?: number
254
255
  proxyBodyTimeout?: number
255
256
  proxyMaxResponseSize?: number
257
+ proxyPreferCompressed?: boolean
256
258
  }
@@ -166,7 +166,9 @@ import * as ToolsOzoneCommunicationUpdateTemplate from './types/tools/ozone/comm
166
166
  import * as ToolsOzoneModerationEmitEvent from './types/tools/ozone/moderation/emitEvent'
167
167
  import * as ToolsOzoneModerationGetEvent from './types/tools/ozone/moderation/getEvent'
168
168
  import * as ToolsOzoneModerationGetRecord from './types/tools/ozone/moderation/getRecord'
169
+ import * as ToolsOzoneModerationGetRecords from './types/tools/ozone/moderation/getRecords'
169
170
  import * as ToolsOzoneModerationGetRepo from './types/tools/ozone/moderation/getRepo'
171
+ import * as ToolsOzoneModerationGetRepos from './types/tools/ozone/moderation/getRepos'
170
172
  import * as ToolsOzoneModerationQueryEvents from './types/tools/ozone/moderation/queryEvents'
171
173
  import * as ToolsOzoneModerationQueryStatuses from './types/tools/ozone/moderation/queryStatuses'
172
174
  import * as ToolsOzoneModerationSearchRepos from './types/tools/ozone/moderation/searchRepos'
@@ -2262,6 +2264,17 @@ export class ToolsOzoneModerationNS {
2262
2264
  return this._server.xrpc.method(nsid, cfg)
2263
2265
  }
2264
2266
 
2267
+ getRecords<AV extends AuthVerifier>(
2268
+ cfg: ConfigOf<
2269
+ AV,
2270
+ ToolsOzoneModerationGetRecords.Handler<ExtractAuth<AV>>,
2271
+ ToolsOzoneModerationGetRecords.HandlerReqCtx<ExtractAuth<AV>>
2272
+ >,
2273
+ ) {
2274
+ const nsid = 'tools.ozone.moderation.getRecords' // @ts-ignore
2275
+ return this._server.xrpc.method(nsid, cfg)
2276
+ }
2277
+
2265
2278
  getRepo<AV extends AuthVerifier>(
2266
2279
  cfg: ConfigOf<
2267
2280
  AV,
@@ -2273,6 +2286,17 @@ export class ToolsOzoneModerationNS {
2273
2286
  return this._server.xrpc.method(nsid, cfg)
2274
2287
  }
2275
2288
 
2289
+ getRepos<AV extends AuthVerifier>(
2290
+ cfg: ConfigOf<
2291
+ AV,
2292
+ ToolsOzoneModerationGetRepos.Handler<ExtractAuth<AV>>,
2293
+ ToolsOzoneModerationGetRepos.HandlerReqCtx<ExtractAuth<AV>>
2294
+ >,
2295
+ ) {
2296
+ const nsid = 'tools.ozone.moderation.getRepos' // @ts-ignore
2297
+ return this._server.xrpc.method(nsid, cfg)
2298
+ }
2299
+
2276
2300
  queryEvents<AV extends AuthVerifier>(
2277
2301
  cfg: ConfigOf<
2278
2302
  AV,
@@ -1686,6 +1686,11 @@ export const schemaDict = {
1686
1686
  },
1687
1687
  },
1688
1688
  },
1689
+ errors: [
1690
+ {
1691
+ name: 'RecordNotFound',
1692
+ },
1693
+ ],
1689
1694
  },
1690
1695
  },
1691
1696
  },
@@ -11643,6 +11648,49 @@ export const schemaDict = {
11643
11648
  },
11644
11649
  },
11645
11650
  },
11651
+ ToolsOzoneModerationGetRecords: {
11652
+ lexicon: 1,
11653
+ id: 'tools.ozone.moderation.getRecords',
11654
+ defs: {
11655
+ main: {
11656
+ type: 'query',
11657
+ description: 'Get details about some records.',
11658
+ parameters: {
11659
+ type: 'params',
11660
+ required: ['uris'],
11661
+ properties: {
11662
+ uris: {
11663
+ type: 'array',
11664
+ maxLength: 100,
11665
+ items: {
11666
+ type: 'string',
11667
+ format: 'at-uri',
11668
+ },
11669
+ },
11670
+ },
11671
+ },
11672
+ output: {
11673
+ encoding: 'application/json',
11674
+ schema: {
11675
+ type: 'object',
11676
+ required: ['records'],
11677
+ properties: {
11678
+ records: {
11679
+ type: 'array',
11680
+ items: {
11681
+ type: 'union',
11682
+ refs: [
11683
+ 'lex:tools.ozone.moderation.defs#recordViewDetail',
11684
+ 'lex:tools.ozone.moderation.defs#recordViewNotFound',
11685
+ ],
11686
+ },
11687
+ },
11688
+ },
11689
+ },
11690
+ },
11691
+ },
11692
+ },
11693
+ },
11646
11694
  ToolsOzoneModerationGetRepo: {
11647
11695
  lexicon: 1,
11648
11696
  id: 'tools.ozone.moderation.getRepo',
@@ -11675,6 +11723,49 @@ export const schemaDict = {
11675
11723
  },
11676
11724
  },
11677
11725
  },
11726
+ ToolsOzoneModerationGetRepos: {
11727
+ lexicon: 1,
11728
+ id: 'tools.ozone.moderation.getRepos',
11729
+ defs: {
11730
+ main: {
11731
+ type: 'query',
11732
+ description: 'Get details about some repositories.',
11733
+ parameters: {
11734
+ type: 'params',
11735
+ required: ['dids'],
11736
+ properties: {
11737
+ dids: {
11738
+ type: 'array',
11739
+ maxLength: 100,
11740
+ items: {
11741
+ type: 'string',
11742
+ format: 'did',
11743
+ },
11744
+ },
11745
+ },
11746
+ },
11747
+ output: {
11748
+ encoding: 'application/json',
11749
+ schema: {
11750
+ type: 'object',
11751
+ required: ['repos'],
11752
+ properties: {
11753
+ repos: {
11754
+ type: 'array',
11755
+ items: {
11756
+ type: 'union',
11757
+ refs: [
11758
+ 'lex:tools.ozone.moderation.defs#repoViewDetail',
11759
+ 'lex:tools.ozone.moderation.defs#repoViewNotFound',
11760
+ ],
11761
+ },
11762
+ },
11763
+ },
11764
+ },
11765
+ },
11766
+ },
11767
+ },
11768
+ },
11678
11769
  ToolsOzoneModerationQueryEvents: {
11679
11770
  lexicon: 1,
11680
11771
  id: 'tools.ozone.moderation.queryEvents',
@@ -12491,7 +12582,9 @@ export const ids = {
12491
12582
  ToolsOzoneModerationEmitEvent: 'tools.ozone.moderation.emitEvent',
12492
12583
  ToolsOzoneModerationGetEvent: 'tools.ozone.moderation.getEvent',
12493
12584
  ToolsOzoneModerationGetRecord: 'tools.ozone.moderation.getRecord',
12585
+ ToolsOzoneModerationGetRecords: 'tools.ozone.moderation.getRecords',
12494
12586
  ToolsOzoneModerationGetRepo: 'tools.ozone.moderation.getRepo',
12587
+ ToolsOzoneModerationGetRepos: 'tools.ozone.moderation.getRepos',
12495
12588
  ToolsOzoneModerationQueryEvents: 'tools.ozone.moderation.queryEvents',
12496
12589
  ToolsOzoneModerationQueryStatuses: 'tools.ozone.moderation.queryStatuses',
12497
12590
  ToolsOzoneModerationSearchRepos: 'tools.ozone.moderation.searchRepos',
@@ -39,6 +39,7 @@ export interface HandlerSuccess {
39
39
  export interface HandlerError {
40
40
  status: number
41
41
  message?: string
42
+ error?: 'RecordNotFound'
42
43
  }
43
44
 
44
45
  export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
@@ -0,0 +1,50 @@
1
+ /**
2
+ * GENERATED CODE - DO NOT MODIFY
3
+ */
4
+ import express from 'express'
5
+ import { ValidationResult, BlobRef } from '@atproto/lexicon'
6
+ import { lexicons } from '../../../../lexicons'
7
+ import { isObj, hasProp } from '../../../../util'
8
+ import { CID } from 'multiformats/cid'
9
+ import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
10
+ import * as ToolsOzoneModerationDefs from './defs'
11
+
12
+ export interface QueryParams {
13
+ uris: string[]
14
+ }
15
+
16
+ export type InputSchema = undefined
17
+
18
+ export interface OutputSchema {
19
+ records: (
20
+ | ToolsOzoneModerationDefs.RecordViewDetail
21
+ | ToolsOzoneModerationDefs.RecordViewNotFound
22
+ | { $type: string; [k: string]: unknown }
23
+ )[]
24
+ [k: string]: unknown
25
+ }
26
+
27
+ export type HandlerInput = undefined
28
+
29
+ export interface HandlerSuccess {
30
+ encoding: 'application/json'
31
+ body: OutputSchema
32
+ headers?: { [key: string]: string }
33
+ }
34
+
35
+ export interface HandlerError {
36
+ status: number
37
+ message?: string
38
+ }
39
+
40
+ export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
41
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
42
+ auth: HA
43
+ params: QueryParams
44
+ input: HandlerInput
45
+ req: express.Request
46
+ res: express.Response
47
+ }
48
+ export type Handler<HA extends HandlerAuth = never> = (
49
+ ctx: HandlerReqCtx<HA>,
50
+ ) => Promise<HandlerOutput> | HandlerOutput
@@ -0,0 +1,50 @@
1
+ /**
2
+ * GENERATED CODE - DO NOT MODIFY
3
+ */
4
+ import express from 'express'
5
+ import { ValidationResult, BlobRef } from '@atproto/lexicon'
6
+ import { lexicons } from '../../../../lexicons'
7
+ import { isObj, hasProp } from '../../../../util'
8
+ import { CID } from 'multiformats/cid'
9
+ import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
10
+ import * as ToolsOzoneModerationDefs from './defs'
11
+
12
+ export interface QueryParams {
13
+ dids: string[]
14
+ }
15
+
16
+ export type InputSchema = undefined
17
+
18
+ export interface OutputSchema {
19
+ repos: (
20
+ | ToolsOzoneModerationDefs.RepoViewDetail
21
+ | ToolsOzoneModerationDefs.RepoViewNotFound
22
+ | { $type: string; [k: string]: unknown }
23
+ )[]
24
+ [k: string]: unknown
25
+ }
26
+
27
+ export type HandlerInput = undefined
28
+
29
+ export interface HandlerSuccess {
30
+ encoding: 'application/json'
31
+ body: OutputSchema
32
+ headers?: { [key: string]: string }
33
+ }
34
+
35
+ export interface HandlerError {
36
+ status: number
37
+ message?: string
38
+ }
39
+
40
+ export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
41
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
42
+ auth: HA
43
+ params: QueryParams
44
+ input: HandlerInput
45
+ req: express.Request
46
+ res: express.Response
47
+ }
48
+ export type Handler<HA extends HandlerAuth = never> = (
49
+ ctx: HandlerReqCtx<HA>,
50
+ ) => Promise<HandlerOutput> | HandlerOutput
@@ -68,7 +68,7 @@
68
68
  style="font-size:16px;line-height:1.4;margin:0px 0px;letter-spacing:0.25px;color:hsl(211, 24%, 34.2%);font-family:-apple-system, BlinkMacSystemFont, &#x27;Roboto&#x27;, &#x27;Oxygen&#x27;, &#x27;Ubuntu&#x27;, &#x27;Cantarell&#x27;, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, sans-serif;padding-top:12px;padding-bottom:12px;padding-right:32px"
69
69
  >To confirm this email for your account, please enter the
70
70
  code below in the app.</p><code
71
- style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:lowercase"
71
+ style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:uppercase"
72
72
  >{{token}}</code>
73
73
  <p
74
74
  style="font-size:14px;line-height:1.4;margin:0px 0px;letter-spacing:0.25px;color:hsl(211, 20%, 53%);font-family:-apple-system, BlinkMacSystemFont, &#x27;Roboto&#x27;, &#x27;Oxygen&#x27;, &#x27;Ubuntu&#x27;, &#x27;Cantarell&#x27;, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, sans-serif;padding-top:12px"
@@ -71,7 +71,7 @@
71
71
  account,</span>
72
72
  <!-- -->please enter the code below in the app along with
73
73
  your password.</p><code
74
- style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:lowercase"
74
+ style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:uppercase"
75
75
  >{{token}}</code>
76
76
  <p
77
77
  style="font-size:14px;line-height:1.4;margin:0px 0px;letter-spacing:0.25px;color:hsl(211, 20%, 53%);font-family:-apple-system, BlinkMacSystemFont, &#x27;Roboto&#x27;, &#x27;Oxygen&#x27;, &#x27;Ubuntu&#x27;, &#x27;Cantarell&#x27;, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, sans-serif;padding-top:12px;padding-right:32px"
@@ -68,7 +68,7 @@
68
68
  style="font-size:16px;line-height:1.4;margin:0px 0px;letter-spacing:0.25px;color:hsl(211, 24%, 34.2%);font-family:-apple-system, BlinkMacSystemFont, &#x27;Roboto&#x27;, &#x27;Oxygen&#x27;, &#x27;Ubuntu&#x27;, &#x27;Cantarell&#x27;, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, sans-serif;padding-top:12px;padding-bottom:12px"
69
69
  >We received a request to update your PLC identity. Your
70
70
  confirmation code is:</p><code
71
- style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:lowercase"
71
+ style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:uppercase"
72
72
  >{{token}}</code>
73
73
  <p
74
74
  style="font-size:14px;line-height:1.4;margin:0px 0px;letter-spacing:0.25px;color:hsl(211, 20%, 53%);font-family:-apple-system, BlinkMacSystemFont, &#x27;Roboto&#x27;, &#x27;Oxygen&#x27;, &#x27;Ubuntu&#x27;, &#x27;Cantarell&#x27;, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, sans-serif;padding-top:12px"
@@ -70,7 +70,7 @@
70
70
  <span
71
71
  style="color:hsl(211, 99%, 53%)"
72
72
  >@<!-- -->{{handle}}<!-- -->.</span></p><code
73
- style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:lowercase"
73
+ style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:uppercase"
74
74
  >{{token}}</code>
75
75
  <p
76
76
  style="font-size:14px;line-height:1.4;margin:0px 0px;letter-spacing:0.25px;color:hsl(211, 20%, 53%);font-family:-apple-system, BlinkMacSystemFont, &#x27;Roboto&#x27;, &#x27;Oxygen&#x27;, &#x27;Ubuntu&#x27;, &#x27;Cantarell&#x27;, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, sans-serif;padding-top:12px"
@@ -69,7 +69,7 @@
69
69
  style="font-size:16px;line-height:1.4;margin:0px 0px;letter-spacing:0.25px;color:hsl(211, 24%, 34.2%);font-family:-apple-system, BlinkMacSystemFont, &#x27;Roboto&#x27;, &#x27;Oxygen&#x27;, &#x27;Ubuntu&#x27;, &#x27;Cantarell&#x27;, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, sans-serif;padding-top:12px;padding-bottom:12px;padding-right:32px"
70
70
  >To update the email for your account, enter the code below
71
71
  in the app along with your new email.</p><code
72
- style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:lowercase"
72
+ style="display:block;padding:16px;border-radius:8px;border-width:1px;border-style:solid;background-color:hsl(211, 20%, 95.3%);border-color:hsl(211, 20%, 85.89999999999999%);font-size:14px;letter-spacing:0.25px;font-family:monospace;text-transform:uppercase"
73
73
  >{{token}}</code>
74
74
  <p
75
75
  style="font-size:14px;line-height:1.4;margin:0px 0px;letter-spacing:0.25px;color:hsl(211, 20%, 53%);font-family:-apple-system, BlinkMacSystemFont, &#x27;Roboto&#x27;, &#x27;Oxygen&#x27;, &#x27;Ubuntu&#x27;, &#x27;Cantarell&#x27;, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, sans-serif;padding-top:12px"