@atproto/ozone 0.1.24 → 0.1.26

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 (121) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +8 -0
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/proxied.d.ts.map +1 -1
  6. package/dist/api/proxied.js +13 -0
  7. package/dist/api/proxied.js.map +1 -1
  8. package/dist/api/server/getConfig.d.ts.map +1 -1
  9. package/dist/api/server/getConfig.js +4 -3
  10. package/dist/api/server/getConfig.js.map +1 -1
  11. package/dist/api/team/addMember.d.ts +4 -0
  12. package/dist/api/team/addMember.d.ts.map +1 -0
  13. package/dist/api/team/addMember.js +38 -0
  14. package/dist/api/team/addMember.js.map +1 -0
  15. package/dist/api/team/deleteMember.d.ts +4 -0
  16. package/dist/api/team/deleteMember.d.ts.map +1 -0
  17. package/dist/api/team/deleteMember.js +26 -0
  18. package/dist/api/team/deleteMember.js.map +1 -0
  19. package/dist/api/team/listMembers.d.ts +4 -0
  20. package/dist/api/team/listMembers.d.ts.map +1 -0
  21. package/dist/api/team/listMembers.js +20 -0
  22. package/dist/api/team/listMembers.js.map +1 -0
  23. package/dist/api/team/updateMember.d.ts +4 -0
  24. package/dist/api/team/updateMember.d.ts.map +1 -0
  25. package/dist/api/team/updateMember.js +40 -0
  26. package/dist/api/team/updateMember.js.map +1 -0
  27. package/dist/api/util.d.ts +1 -0
  28. package/dist/api/util.d.ts.map +1 -1
  29. package/dist/api/util.js +10 -1
  30. package/dist/api/util.js.map +1 -1
  31. package/dist/auth-verifier.d.ts +3 -6
  32. package/dist/auth-verifier.d.ts.map +1 -1
  33. package/dist/auth-verifier.js +7 -19
  34. package/dist/auth-verifier.js.map +1 -1
  35. package/dist/config/config.d.ts.map +1 -1
  36. package/dist/config/config.js +10 -7
  37. package/dist/config/config.js.map +1 -1
  38. package/dist/context.d.ts +3 -0
  39. package/dist/context.d.ts.map +1 -1
  40. package/dist/context.js +7 -3
  41. package/dist/context.js.map +1 -1
  42. package/dist/db/migrations/20240521T211332580Z-member.d.ts +4 -0
  43. package/dist/db/migrations/20240521T211332580Z-member.d.ts.map +1 -0
  44. package/dist/db/migrations/20240521T211332580Z-member.js +20 -0
  45. package/dist/db/migrations/20240521T211332580Z-member.js.map +1 -0
  46. package/dist/db/migrations/index.d.ts +1 -0
  47. package/dist/db/migrations/index.d.ts.map +1 -1
  48. package/dist/db/migrations/index.js +2 -1
  49. package/dist/db/migrations/index.js.map +1 -1
  50. package/dist/db/schema/index.d.ts +2 -1
  51. package/dist/db/schema/index.d.ts.map +1 -1
  52. package/dist/db/schema/member.d.ts +14 -0
  53. package/dist/db/schema/member.d.ts.map +1 -0
  54. package/dist/db/schema/member.js +5 -0
  55. package/dist/db/schema/member.js.map +1 -0
  56. package/dist/index.d.ts +1 -0
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +25 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/lexicon/index.d.ts +18 -0
  61. package/dist/lexicon/index.d.ts.map +1 -1
  62. package/dist/lexicon/index.js +41 -1
  63. package/dist/lexicon/index.js.map +1 -1
  64. package/dist/lexicon/lexicons.d.ts +204 -0
  65. package/dist/lexicon/lexicons.d.ts.map +1 -1
  66. package/dist/lexicon/lexicons.js +222 -0
  67. package/dist/lexicon/lexicons.js.map +1 -1
  68. package/dist/lexicon/types/tools/ozone/team/addMember.d.ts +40 -0
  69. package/dist/lexicon/types/tools/ozone/team/addMember.d.ts.map +1 -0
  70. package/dist/lexicon/types/tools/ozone/team/addMember.js +3 -0
  71. package/dist/lexicon/types/tools/ozone/team/addMember.js.map +1 -0
  72. package/dist/lexicon/types/tools/ozone/team/defs.d.ts +24 -0
  73. package/dist/lexicon/types/tools/ozone/team/defs.d.ts.map +1 -0
  74. package/dist/lexicon/types/tools/ozone/team/defs.js +22 -0
  75. package/dist/lexicon/types/tools/ozone/team/defs.js.map +1 -0
  76. package/dist/lexicon/types/tools/ozone/team/deleteMember.d.ts +30 -0
  77. package/dist/lexicon/types/tools/ozone/team/deleteMember.d.ts.map +1 -0
  78. package/dist/lexicon/types/tools/ozone/team/deleteMember.js +3 -0
  79. package/dist/lexicon/types/tools/ozone/team/deleteMember.js.map +1 -0
  80. package/dist/lexicon/types/tools/ozone/team/listMembers.d.ts +38 -0
  81. package/dist/lexicon/types/tools/ozone/team/listMembers.d.ts.map +1 -0
  82. package/dist/lexicon/types/tools/ozone/team/listMembers.js +3 -0
  83. package/dist/lexicon/types/tools/ozone/team/listMembers.js.map +1 -0
  84. package/dist/lexicon/types/tools/ozone/team/updateMember.d.ts +41 -0
  85. package/dist/lexicon/types/tools/ozone/team/updateMember.d.ts.map +1 -0
  86. package/dist/lexicon/types/tools/ozone/team/updateMember.js +3 -0
  87. package/dist/lexicon/types/tools/ozone/team/updateMember.js.map +1 -0
  88. package/dist/logger.d.ts +2 -1
  89. package/dist/logger.d.ts.map +1 -1
  90. package/dist/team/index.d.ts +37 -0
  91. package/dist/team/index.d.ts.map +1 -0
  92. package/dist/team/index.js +144 -0
  93. package/dist/team/index.js.map +1 -0
  94. package/package.json +3 -3
  95. package/src/api/index.ts +8 -0
  96. package/src/api/proxied.ts +17 -0
  97. package/src/api/server/getConfig.ts +4 -4
  98. package/src/api/team/addMember.ts +46 -0
  99. package/src/api/team/deleteMember.ts +29 -0
  100. package/src/api/team/listMembers.ts +20 -0
  101. package/src/api/team/updateMember.ts +47 -0
  102. package/src/api/util.ts +15 -0
  103. package/src/auth-verifier.ts +14 -12
  104. package/src/config/config.ts +10 -7
  105. package/src/context.ts +9 -3
  106. package/src/db/migrations/20240521T211332580Z-member.ts +17 -0
  107. package/src/db/migrations/index.ts +1 -0
  108. package/src/db/schema/index.ts +3 -1
  109. package/src/db/schema/member.ts +19 -0
  110. package/src/index.ts +36 -0
  111. package/src/lexicon/index.ts +63 -0
  112. package/src/lexicon/lexicons.ts +225 -0
  113. package/src/lexicon/types/tools/ozone/team/addMember.ts +53 -0
  114. package/src/lexicon/types/tools/ozone/team/defs.ts +42 -0
  115. package/src/lexicon/types/tools/ozone/team/deleteMember.ts +39 -0
  116. package/src/lexicon/types/tools/ozone/team/listMembers.ts +48 -0
  117. package/src/lexicon/types/tools/ozone/team/updateMember.ts +54 -0
  118. package/src/team/index.ts +213 -0
  119. package/tests/__snapshots__/team.test.ts.snap +664 -0
  120. package/tests/get-config.test.ts +3 -4
  121. package/tests/team.test.ts +163 -0
@@ -11006,6 +11006,226 @@ export const schemaDict = {
11006
11006
  },
11007
11007
  },
11008
11008
  },
11009
+ ToolsOzoneTeamAddMember: {
11010
+ lexicon: 1,
11011
+ id: 'tools.ozone.team.addMember',
11012
+ defs: {
11013
+ main: {
11014
+ type: 'procedure',
11015
+ description: 'Add a member to the ozone team. Requires admin role.',
11016
+ input: {
11017
+ encoding: 'application/json',
11018
+ schema: {
11019
+ type: 'object',
11020
+ required: ['did', 'role'],
11021
+ properties: {
11022
+ did: {
11023
+ type: 'string',
11024
+ format: 'did',
11025
+ },
11026
+ role: {
11027
+ type: 'string',
11028
+ knownValues: [
11029
+ 'tools.ozone.team.defs#roleAdmin',
11030
+ 'tools.ozone.team.defs#roleModerator',
11031
+ 'tools.ozone.team.defs#roleTriage',
11032
+ ],
11033
+ },
11034
+ },
11035
+ },
11036
+ },
11037
+ output: {
11038
+ encoding: 'application/json',
11039
+ schema: {
11040
+ type: 'ref',
11041
+ ref: 'lex:tools.ozone.team.defs#member',
11042
+ },
11043
+ },
11044
+ errors: [
11045
+ {
11046
+ name: 'MemberAlreadyExists',
11047
+ description: 'Member already exists in the team.',
11048
+ },
11049
+ ],
11050
+ },
11051
+ },
11052
+ },
11053
+ ToolsOzoneTeamDefs: {
11054
+ lexicon: 1,
11055
+ id: 'tools.ozone.team.defs',
11056
+ defs: {
11057
+ member: {
11058
+ type: 'object',
11059
+ required: ['did', 'role'],
11060
+ properties: {
11061
+ did: {
11062
+ type: 'string',
11063
+ format: 'did',
11064
+ },
11065
+ disabled: {
11066
+ type: 'boolean',
11067
+ },
11068
+ profile: {
11069
+ type: 'ref',
11070
+ ref: 'lex:app.bsky.actor.defs#profileViewDetailed',
11071
+ },
11072
+ createdAt: {
11073
+ type: 'string',
11074
+ format: 'datetime',
11075
+ },
11076
+ updatedAt: {
11077
+ type: 'string',
11078
+ format: 'datetime',
11079
+ },
11080
+ lastUpdatedBy: {
11081
+ type: 'string',
11082
+ },
11083
+ role: {
11084
+ type: 'string',
11085
+ knownValues: [
11086
+ 'lex:tools.ozone.team.defs#roleAdmin',
11087
+ 'lex:tools.ozone.team.defs#roleModerator',
11088
+ 'lex:tools.ozone.team.defs#roleTriage',
11089
+ ],
11090
+ },
11091
+ },
11092
+ },
11093
+ roleAdmin: {
11094
+ type: 'token',
11095
+ description:
11096
+ 'Admin role. Highest level of access, can perform all actions.',
11097
+ },
11098
+ roleModerator: {
11099
+ type: 'token',
11100
+ description: 'Moderator role. Can perform most actions.',
11101
+ },
11102
+ roleTriage: {
11103
+ type: 'token',
11104
+ description:
11105
+ 'Triage role. Mostly intended for monitoring and escalating issues.',
11106
+ },
11107
+ },
11108
+ },
11109
+ ToolsOzoneTeamDeleteMember: {
11110
+ lexicon: 1,
11111
+ id: 'tools.ozone.team.deleteMember',
11112
+ defs: {
11113
+ main: {
11114
+ type: 'procedure',
11115
+ description: 'Delete a member from ozone team. Requires admin role.',
11116
+ input: {
11117
+ encoding: 'application/json',
11118
+ schema: {
11119
+ type: 'object',
11120
+ required: ['did'],
11121
+ properties: {
11122
+ did: {
11123
+ type: 'string',
11124
+ format: 'did',
11125
+ },
11126
+ },
11127
+ },
11128
+ },
11129
+ errors: [
11130
+ {
11131
+ name: 'MemberNotFound',
11132
+ description: 'The member being deleted does not exist',
11133
+ },
11134
+ ],
11135
+ },
11136
+ },
11137
+ },
11138
+ ToolsOzoneTeamListMembers: {
11139
+ lexicon: 1,
11140
+ id: 'tools.ozone.team.listMembers',
11141
+ defs: {
11142
+ main: {
11143
+ type: 'query',
11144
+ description: 'List all members with access to the ozone service.',
11145
+ parameters: {
11146
+ type: 'params',
11147
+ properties: {
11148
+ limit: {
11149
+ type: 'integer',
11150
+ minimum: 1,
11151
+ maximum: 100,
11152
+ default: 50,
11153
+ },
11154
+ cursor: {
11155
+ type: 'string',
11156
+ },
11157
+ },
11158
+ },
11159
+ output: {
11160
+ encoding: 'application/json',
11161
+ schema: {
11162
+ type: 'object',
11163
+ required: ['members'],
11164
+ properties: {
11165
+ cursor: {
11166
+ type: 'string',
11167
+ },
11168
+ members: {
11169
+ type: 'array',
11170
+ items: {
11171
+ type: 'ref',
11172
+ ref: 'lex:tools.ozone.team.defs#member',
11173
+ },
11174
+ },
11175
+ },
11176
+ },
11177
+ },
11178
+ },
11179
+ },
11180
+ },
11181
+ ToolsOzoneTeamUpdateMember: {
11182
+ lexicon: 1,
11183
+ id: 'tools.ozone.team.updateMember',
11184
+ defs: {
11185
+ main: {
11186
+ type: 'procedure',
11187
+ description:
11188
+ 'Update a member in the ozone service. Requires admin role.',
11189
+ input: {
11190
+ encoding: 'application/json',
11191
+ schema: {
11192
+ type: 'object',
11193
+ required: ['did'],
11194
+ properties: {
11195
+ did: {
11196
+ type: 'string',
11197
+ format: 'did',
11198
+ },
11199
+ disabled: {
11200
+ type: 'boolean',
11201
+ },
11202
+ role: {
11203
+ type: 'string',
11204
+ knownValues: [
11205
+ 'tools.ozone.team.defs#roleAdmin',
11206
+ 'tools.ozone.team.defs#roleModerator',
11207
+ 'tools.ozone.team.defs#roleTriage',
11208
+ ],
11209
+ },
11210
+ },
11211
+ },
11212
+ },
11213
+ output: {
11214
+ encoding: 'application/json',
11215
+ schema: {
11216
+ type: 'ref',
11217
+ ref: 'lex:tools.ozone.team.defs#member',
11218
+ },
11219
+ },
11220
+ errors: [
11221
+ {
11222
+ name: 'MemberNotFound',
11223
+ description: 'The member being updated does not exist in the team',
11224
+ },
11225
+ ],
11226
+ },
11227
+ },
11228
+ },
11009
11229
  }
11010
11230
  export const schemas: LexiconDoc[] = Object.values(schemaDict) as LexiconDoc[]
11011
11231
  export const lexicons: Lexicons = new Lexicons(schemas)
@@ -11216,4 +11436,9 @@ export const ids = {
11216
11436
  ToolsOzoneModerationQueryStatuses: 'tools.ozone.moderation.queryStatuses',
11217
11437
  ToolsOzoneModerationSearchRepos: 'tools.ozone.moderation.searchRepos',
11218
11438
  ToolsOzoneServerGetConfig: 'tools.ozone.server.getConfig',
11439
+ ToolsOzoneTeamAddMember: 'tools.ozone.team.addMember',
11440
+ ToolsOzoneTeamDefs: 'tools.ozone.team.defs',
11441
+ ToolsOzoneTeamDeleteMember: 'tools.ozone.team.deleteMember',
11442
+ ToolsOzoneTeamListMembers: 'tools.ozone.team.listMembers',
11443
+ ToolsOzoneTeamUpdateMember: 'tools.ozone.team.updateMember',
11219
11444
  }
@@ -0,0 +1,53 @@
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 ToolsOzoneTeamDefs from './defs'
11
+
12
+ export interface QueryParams {}
13
+
14
+ export interface InputSchema {
15
+ did: string
16
+ role:
17
+ | 'tools.ozone.team.defs#roleAdmin'
18
+ | 'tools.ozone.team.defs#roleModerator'
19
+ | 'tools.ozone.team.defs#roleTriage'
20
+ | (string & {})
21
+ [k: string]: unknown
22
+ }
23
+
24
+ export type OutputSchema = ToolsOzoneTeamDefs.Member
25
+
26
+ export interface HandlerInput {
27
+ encoding: 'application/json'
28
+ body: InputSchema
29
+ }
30
+
31
+ export interface HandlerSuccess {
32
+ encoding: 'application/json'
33
+ body: OutputSchema
34
+ headers?: { [key: string]: string }
35
+ }
36
+
37
+ export interface HandlerError {
38
+ status: number
39
+ message?: string
40
+ error?: 'MemberAlreadyExists'
41
+ }
42
+
43
+ export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
44
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
45
+ auth: HA
46
+ params: QueryParams
47
+ input: HandlerInput
48
+ req: express.Request
49
+ res: express.Response
50
+ }
51
+ export type Handler<HA extends HandlerAuth = never> = (
52
+ ctx: HandlerReqCtx<HA>,
53
+ ) => Promise<HandlerOutput> | HandlerOutput
@@ -0,0 +1,42 @@
1
+ /**
2
+ * GENERATED CODE - DO NOT MODIFY
3
+ */
4
+ import { ValidationResult, BlobRef } from '@atproto/lexicon'
5
+ import { lexicons } from '../../../../lexicons'
6
+ import { isObj, hasProp } from '../../../../util'
7
+ import { CID } from 'multiformats/cid'
8
+ import * as AppBskyActorDefs from '../../../app/bsky/actor/defs'
9
+
10
+ export interface Member {
11
+ did: string
12
+ disabled?: boolean
13
+ profile?: AppBskyActorDefs.ProfileViewDetailed
14
+ createdAt?: string
15
+ updatedAt?: string
16
+ lastUpdatedBy?: string
17
+ role:
18
+ | 'lex:tools.ozone.team.defs#roleAdmin'
19
+ | 'lex:tools.ozone.team.defs#roleModerator'
20
+ | 'lex:tools.ozone.team.defs#roleTriage'
21
+ | (string & {})
22
+ [k: string]: unknown
23
+ }
24
+
25
+ export function isMember(v: unknown): v is Member {
26
+ return (
27
+ isObj(v) &&
28
+ hasProp(v, '$type') &&
29
+ v.$type === 'tools.ozone.team.defs#member'
30
+ )
31
+ }
32
+
33
+ export function validateMember(v: unknown): ValidationResult {
34
+ return lexicons.validate('tools.ozone.team.defs#member', v)
35
+ }
36
+
37
+ /** Admin role. Highest level of access, can perform all actions. */
38
+ export const ROLEADMIN = 'tools.ozone.team.defs#roleAdmin'
39
+ /** Moderator role. Can perform most actions. */
40
+ export const ROLEMODERATOR = 'tools.ozone.team.defs#roleModerator'
41
+ /** Triage role. Mostly intended for monitoring and escalating issues. */
42
+ export const ROLETRIAGE = 'tools.ozone.team.defs#roleTriage'
@@ -0,0 +1,39 @@
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
+
11
+ export interface QueryParams {}
12
+
13
+ export interface InputSchema {
14
+ did: string
15
+ [k: string]: unknown
16
+ }
17
+
18
+ export interface HandlerInput {
19
+ encoding: 'application/json'
20
+ body: InputSchema
21
+ }
22
+
23
+ export interface HandlerError {
24
+ status: number
25
+ message?: string
26
+ error?: 'MemberNotFound'
27
+ }
28
+
29
+ export type HandlerOutput = HandlerError | void
30
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
31
+ auth: HA
32
+ params: QueryParams
33
+ input: HandlerInput
34
+ req: express.Request
35
+ res: express.Response
36
+ }
37
+ export type Handler<HA extends HandlerAuth = never> = (
38
+ ctx: HandlerReqCtx<HA>,
39
+ ) => Promise<HandlerOutput> | HandlerOutput
@@ -0,0 +1,48 @@
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 ToolsOzoneTeamDefs from './defs'
11
+
12
+ export interface QueryParams {
13
+ limit: number
14
+ cursor?: string
15
+ }
16
+
17
+ export type InputSchema = undefined
18
+
19
+ export interface OutputSchema {
20
+ cursor?: string
21
+ members: ToolsOzoneTeamDefs.Member[]
22
+ [k: string]: unknown
23
+ }
24
+
25
+ export type HandlerInput = undefined
26
+
27
+ export interface HandlerSuccess {
28
+ encoding: 'application/json'
29
+ body: OutputSchema
30
+ headers?: { [key: string]: string }
31
+ }
32
+
33
+ export interface HandlerError {
34
+ status: number
35
+ message?: string
36
+ }
37
+
38
+ export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
39
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
40
+ auth: HA
41
+ params: QueryParams
42
+ input: HandlerInput
43
+ req: express.Request
44
+ res: express.Response
45
+ }
46
+ export type Handler<HA extends HandlerAuth = never> = (
47
+ ctx: HandlerReqCtx<HA>,
48
+ ) => Promise<HandlerOutput> | HandlerOutput
@@ -0,0 +1,54 @@
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 ToolsOzoneTeamDefs from './defs'
11
+
12
+ export interface QueryParams {}
13
+
14
+ export interface InputSchema {
15
+ did: string
16
+ disabled?: boolean
17
+ role?:
18
+ | 'tools.ozone.team.defs#roleAdmin'
19
+ | 'tools.ozone.team.defs#roleModerator'
20
+ | 'tools.ozone.team.defs#roleTriage'
21
+ | (string & {})
22
+ [k: string]: unknown
23
+ }
24
+
25
+ export type OutputSchema = ToolsOzoneTeamDefs.Member
26
+
27
+ export interface HandlerInput {
28
+ encoding: 'application/json'
29
+ body: InputSchema
30
+ }
31
+
32
+ export interface HandlerSuccess {
33
+ encoding: 'application/json'
34
+ body: OutputSchema
35
+ headers?: { [key: string]: string }
36
+ }
37
+
38
+ export interface HandlerError {
39
+ status: number
40
+ message?: string
41
+ error?: 'MemberNotFound'
42
+ }
43
+
44
+ export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
45
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
46
+ auth: HA
47
+ params: QueryParams
48
+ input: HandlerInput
49
+ req: express.Request
50
+ res: express.Response
51
+ }
52
+ export type Handler<HA extends HandlerAuth = never> = (
53
+ ctx: HandlerReqCtx<HA>,
54
+ ) => Promise<HandlerOutput> | HandlerOutput
@@ -0,0 +1,213 @@
1
+ import Database from '../db'
2
+ import { Selectable } from 'kysely'
3
+ import { Member } from '../db/schema/member'
4
+ import { Member as TeamMember } from '../lexicon/types/tools/ozone/team/defs'
5
+ import { ProfileViewDetailed } from '../lexicon/types/app/bsky/actor/defs'
6
+ import { InvalidRequestError } from '@atproto/xrpc-server'
7
+ import { chunkArray } from '@atproto/common'
8
+ import AppContext from '../context'
9
+ import { httpLogger } from '../logger'
10
+
11
+ export type TeamServiceCreator = (db: Database) => TeamService
12
+
13
+ export class TeamService {
14
+ constructor(public db: Database) {}
15
+
16
+ static creator() {
17
+ return (db: Database) => new TeamService(db)
18
+ }
19
+
20
+ async list({
21
+ cursor,
22
+ limit = 25,
23
+ }: {
24
+ cursor?: string
25
+ limit?: number
26
+ }): Promise<{ members: Selectable<Member>[]; cursor?: string }> {
27
+ let builder = this.db.db.selectFrom('member').selectAll()
28
+ if (cursor) {
29
+ builder = builder.where('createdAt', '>', new Date(cursor))
30
+ }
31
+ const members = await builder
32
+ .limit(limit)
33
+ .orderBy('createdAt', 'asc')
34
+ .execute()
35
+
36
+ return { members, cursor: members.at(-1)?.createdAt.toISOString() }
37
+ }
38
+
39
+ async create({
40
+ role,
41
+ did,
42
+ disabled,
43
+ updatedAt,
44
+ createdAt,
45
+ lastUpdatedBy,
46
+ }: Omit<Selectable<Member>, 'createdAt' | 'updatedAt'> & {
47
+ createdAt?: Date
48
+ updatedAt?: Date
49
+ }): Promise<Selectable<Member>> {
50
+ const now = new Date()
51
+ const newMember = await this.db.db
52
+ .insertInto('member')
53
+ .values({
54
+ role,
55
+ did,
56
+ disabled,
57
+ lastUpdatedBy,
58
+ updatedAt: updatedAt || now,
59
+ createdAt: createdAt || now,
60
+ })
61
+ .returningAll()
62
+ .executeTakeFirstOrThrow()
63
+
64
+ return newMember
65
+ }
66
+
67
+ async upsert({
68
+ role,
69
+ did,
70
+ lastUpdatedBy,
71
+ }: Pick<
72
+ Selectable<Member>,
73
+ 'role' | 'did' | 'lastUpdatedBy'
74
+ >): Promise<void> {
75
+ const now = new Date()
76
+ await this.db.db
77
+ .insertInto('member')
78
+ .values({
79
+ role,
80
+ did,
81
+ lastUpdatedBy,
82
+ disabled: false,
83
+ updatedAt: now,
84
+ createdAt: now,
85
+ })
86
+ .onConflict((oc) =>
87
+ oc.column('did').doUpdateSet({ role, updatedAt: now, lastUpdatedBy }),
88
+ )
89
+ .execute()
90
+ }
91
+
92
+ async update(
93
+ did: string,
94
+ updates: Partial<
95
+ Pick<
96
+ Selectable<Member>,
97
+ 'role' | 'disabled' | 'lastUpdatedBy' | 'updatedAt'
98
+ >
99
+ >,
100
+ ): Promise<Selectable<Member>> {
101
+ const { role, disabled, lastUpdatedBy, updatedAt = new Date() } = updates
102
+ const updatedMember = await this.db.db
103
+ .updateTable('member')
104
+ .where('did', '=', did)
105
+ .set({
106
+ role,
107
+ disabled,
108
+ lastUpdatedBy,
109
+ updatedAt,
110
+ })
111
+ .returningAll()
112
+ .executeTakeFirstOrThrow()
113
+
114
+ return updatedMember
115
+ }
116
+
117
+ async delete(did: string): Promise<void> {
118
+ await this.db.db.deleteFrom('member').where('did', '=', did).execute()
119
+ }
120
+
121
+ async assertCanDelete(did: string): Promise<void> {
122
+ const memberExists = await this.doesMemberExist(did)
123
+
124
+ if (!memberExists) {
125
+ throw new InvalidRequestError('member not found', 'MemberNotFound')
126
+ }
127
+ }
128
+
129
+ async doesMemberExist(did: string): Promise<boolean> {
130
+ const member = await this.db.db
131
+ .selectFrom('member')
132
+ .select('did')
133
+ .where('did', '=', did)
134
+ .executeTakeFirst()
135
+
136
+ return !!member
137
+ }
138
+
139
+ async getMember(did: string): Promise<Selectable<Member> | undefined> {
140
+ const member = await this.db.db
141
+ .selectFrom('member')
142
+ .selectAll()
143
+ .where('did', '=', did)
144
+ .executeTakeFirst()
145
+
146
+ return member
147
+ }
148
+
149
+ getMemberRole(member?: Selectable<Member>) {
150
+ const isAdmin = member?.role === 'tools.ozone.team.defs#roleAdmin'
151
+ const isModerator =
152
+ isAdmin || member?.role === 'tools.ozone.team.defs#roleModerator'
153
+ const isTriage =
154
+ isModerator || member?.role === 'tools.ozone.team.defs#roleTriage'
155
+
156
+ return {
157
+ isModerator,
158
+ isAdmin,
159
+ isTriage,
160
+ }
161
+ }
162
+
163
+ // getProfiles() only allows 25 DIDs at a time so we need to query in chunks
164
+ async getProfiles(
165
+ dids: string[],
166
+ ctx: AppContext,
167
+ ): Promise<Map<string, ProfileViewDetailed>> {
168
+ const profiles = new Map<string, ProfileViewDetailed>()
169
+
170
+ try {
171
+ const headers = await ctx.appviewAuth()
172
+
173
+ for (const actors of chunkArray(dids, 25)) {
174
+ const { data } = await ctx.appviewAgent.api.app.bsky.actor.getProfiles(
175
+ { actors },
176
+ headers,
177
+ )
178
+
179
+ data.profiles.forEach((profile) => {
180
+ profiles.set(profile.did, profile)
181
+ })
182
+ }
183
+ } catch (error) {
184
+ httpLogger.error(
185
+ { error, dids },
186
+ 'Failed to get profiles for team members',
187
+ )
188
+ }
189
+
190
+ return profiles
191
+ }
192
+
193
+ async view(
194
+ members: Selectable<Member>[],
195
+ ctx: AppContext,
196
+ ): Promise<TeamMember[]> {
197
+ const profiles = await this.getProfiles(
198
+ members.map(({ did }) => did),
199
+ ctx,
200
+ )
201
+ return members.map((member) => {
202
+ return {
203
+ did: member.did,
204
+ role: member.role,
205
+ disabled: member.disabled,
206
+ profile: profiles.get(member.did),
207
+ createdAt: member.createdAt.toISOString(),
208
+ updatedAt: member.updatedAt.toISOString(),
209
+ lastUpdatedBy: member.lastUpdatedBy,
210
+ }
211
+ })
212
+ }
213
+ }