@atproto/ozone 0.1.87 → 0.1.88

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 (64) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/api/team/addMember.d.ts.map +1 -1
  3. package/dist/api/team/addMember.js +5 -1
  4. package/dist/api/team/addMember.js.map +1 -1
  5. package/dist/api/team/listMembers.js +1 -1
  6. package/dist/api/team/listMembers.js.map +1 -1
  7. package/dist/api/team/updateMember.js +1 -1
  8. package/dist/api/team/updateMember.js.map +1 -1
  9. package/dist/config/config.d.ts +1 -0
  10. package/dist/config/config.d.ts.map +1 -1
  11. package/dist/config/config.js +1 -0
  12. package/dist/config/config.js.map +1 -1
  13. package/dist/config/env.d.ts +1 -0
  14. package/dist/config/env.d.ts.map +1 -1
  15. package/dist/config/env.js +1 -0
  16. package/dist/config/env.js.map +1 -1
  17. package/dist/context.d.ts.map +1 -1
  18. package/dist/context.js +1 -1
  19. package/dist/context.js.map +1 -1
  20. package/dist/daemon/context.d.ts +3 -0
  21. package/dist/daemon/context.d.ts.map +1 -1
  22. package/dist/daemon/context.js +11 -0
  23. package/dist/daemon/context.js.map +1 -1
  24. package/dist/daemon/team-profile-synchronizer.d.ts +6 -0
  25. package/dist/daemon/team-profile-synchronizer.d.ts.map +1 -0
  26. package/dist/daemon/team-profile-synchronizer.js +14 -0
  27. package/dist/daemon/team-profile-synchronizer.js.map +1 -0
  28. package/dist/db/migrations/20250221T132135150Z-member-details.d.ts +4 -0
  29. package/dist/db/migrations/20250221T132135150Z-member-details.d.ts.map +1 -0
  30. package/dist/db/migrations/20250221T132135150Z-member-details.js +16 -0
  31. package/dist/db/migrations/20250221T132135150Z-member-details.js.map +1 -0
  32. package/dist/db/migrations/index.d.ts +1 -0
  33. package/dist/db/migrations/index.d.ts.map +1 -1
  34. package/dist/db/migrations/index.js +2 -1
  35. package/dist/db/migrations/index.js.map +1 -1
  36. package/dist/db/schema/member.d.ts +2 -0
  37. package/dist/db/schema/member.d.ts.map +1 -1
  38. package/dist/lexicon/lexicons.d.ts +6 -0
  39. package/dist/lexicon/lexicons.d.ts.map +1 -1
  40. package/dist/lexicon/lexicons.js +3 -0
  41. package/dist/lexicon/lexicons.js.map +1 -1
  42. package/dist/lexicon/types/tools/ozone/team/listMembers.d.ts +1 -0
  43. package/dist/lexicon/types/tools/ozone/team/listMembers.d.ts.map +1 -1
  44. package/dist/team/index.d.ts +12 -6
  45. package/dist/team/index.d.ts.map +1 -1
  46. package/dist/team/index.js +58 -9
  47. package/dist/team/index.js.map +1 -1
  48. package/package.json +3 -3
  49. package/src/api/team/addMember.ts +6 -1
  50. package/src/api/team/listMembers.ts +1 -1
  51. package/src/api/team/updateMember.ts +1 -1
  52. package/src/config/config.ts +2 -0
  53. package/src/config/env.ts +4 -0
  54. package/src/context.ts +5 -1
  55. package/src/daemon/context.ts +21 -0
  56. package/src/daemon/team-profile-synchronizer.ts +15 -0
  57. package/src/db/migrations/20250221T132135150Z-member-details.ts +14 -0
  58. package/src/db/migrations/index.ts +1 -0
  59. package/src/db/schema/member.ts +2 -0
  60. package/src/lexicon/lexicons.ts +3 -0
  61. package/src/lexicon/types/tools/ozone/team/listMembers.ts +1 -0
  62. package/src/team/index.ts +66 -18
  63. package/tests/team.test.ts +23 -0
  64. package/tsconfig.build.tsbuildinfo +1 -1
@@ -5,6 +5,7 @@ import express from 'express';
5
5
  import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server';
6
6
  import type * as ToolsOzoneTeamDefs from './defs.js';
7
7
  export interface QueryParams {
8
+ q?: string;
8
9
  disabled?: boolean;
9
10
  roles?: string[];
10
11
  limit: number;
@@ -1 +1 @@
1
- {"version":3,"file":"listMembers.d.ts","sourceRoot":"","sources":["../../../../../../src/lexicon/types/tools/ozone/team/listMembers.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,OAAO,MAAM,SAAS,CAAA;AAK7B,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACtE,OAAO,KAAK,KAAK,kBAAkB,MAAM,WAAW,CAAA;AAMpD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,WAAW,GAAG,SAAS,CAAA;AAEnC,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,kBAAkB,CAAC,MAAM,EAAE,CAAA;CACrC;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,CAAA;AAEpC,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,IAAI,EAAE,YAAY,CAAA;IAClB,OAAO,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,cAAc,GAAG,kBAAkB,CAAA;AAC9E,MAAM,MAAM,aAAa,CAAC,EAAE,SAAS,WAAW,GAAG,KAAK,IAAI;IAC1D,IAAI,EAAE,EAAE,CAAA;IACR,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,YAAY,CAAA;IACnB,GAAG,EAAE,OAAO,CAAC,OAAO,CAAA;IACpB,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAA;IACrB,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1C,CAAA;AACD,MAAM,MAAM,OAAO,CAAC,EAAE,SAAS,WAAW,GAAG,KAAK,IAAI,CACpD,GAAG,EAAE,aAAa,CAAC,EAAE,CAAC,KACnB,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa,CAAA"}
1
+ {"version":3,"file":"listMembers.d.ts","sourceRoot":"","sources":["../../../../../../src/lexicon/types/tools/ozone/team/listMembers.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,OAAO,MAAM,SAAS,CAAA;AAK7B,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACtE,OAAO,KAAK,KAAK,kBAAkB,MAAM,WAAW,CAAA;AAMpD,MAAM,WAAW,WAAW;IAC1B,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,WAAW,GAAG,SAAS,CAAA;AAEnC,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,kBAAkB,CAAC,MAAM,EAAE,CAAA;CACrC;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,CAAA;AAEpC,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,IAAI,EAAE,YAAY,CAAA;IAClB,OAAO,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,cAAc,GAAG,kBAAkB,CAAA;AAC9E,MAAM,MAAM,aAAa,CAAC,EAAE,SAAS,WAAW,GAAG,KAAK,IAAI;IAC1D,IAAI,EAAE,EAAE,CAAA;IACR,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,YAAY,CAAA;IACnB,GAAG,EAAE,OAAO,CAAC,OAAO,CAAA;IACpB,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAA;IACrB,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1C,CAAA;AACD,MAAM,MAAM,OAAO,CAAC,EAAE,SAAS,WAAW,GAAG,KAAK,IAAI,CACpD,GAAG,EAAE,aAAa,CAAC,EAAE,CAAC,KACnB,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa,CAAA"}
@@ -1,15 +1,20 @@
1
1
  import { Selectable } from 'kysely';
2
- import { AppContext } from '../context';
2
+ import AtpAgent from '@atproto/api';
3
3
  import { Database } from '../db';
4
4
  import { Member } from '../db/schema/member';
5
5
  import { ProfileViewDetailed } from '../lexicon/types/app/bsky/actor/defs';
6
6
  import { Member as TeamMember } from '../lexicon/types/tools/ozone/team/defs';
7
+ import { AuthHeaders } from '../mod-service/views';
7
8
  export type TeamServiceCreator = (db: Database) => TeamService;
8
9
  export declare class TeamService {
9
10
  db: Database;
10
- constructor(db: Database);
11
- static creator(): (db: Database) => TeamService;
12
- list({ cursor, limit, roles, disabled, }: {
11
+ private appviewAgent;
12
+ private appviewDid;
13
+ private createAuthHeaders;
14
+ constructor(db: Database, appviewAgent: AtpAgent, appviewDid: string, createAuthHeaders: (aud: string, method: string) => Promise<AuthHeaders>);
15
+ static creator(appviewAgent: AtpAgent, appviewDid: string, createAuthHeaders: (aud: string, method: string) => Promise<AuthHeaders>): (db: Database) => TeamService;
16
+ list({ cursor, limit, roles, disabled, q, }: {
17
+ q?: string;
13
18
  cursor?: string;
14
19
  limit?: number;
15
20
  disabled?: boolean;
@@ -33,7 +38,8 @@ export declare class TeamService {
33
38
  isAdmin: boolean;
34
39
  isTriage: boolean;
35
40
  };
36
- getProfiles(dids: string[], ctx: AppContext): Promise<Map<string, ProfileViewDetailed>>;
37
- view(members: Selectable<Member>[], ctx: AppContext): Promise<TeamMember[]>;
41
+ getProfiles(dids: string[]): Promise<Map<string, ProfileViewDetailed>>;
42
+ syncMemberProfiles(): Promise<void>;
43
+ view(members: Selectable<Member>[]): Promise<TeamMember[]>;
38
44
  }
39
45
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/team/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAGnC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAE5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAA;AAC1E,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,wCAAwC,CAAA;AAG7E,MAAM,MAAM,kBAAkB,GAAG,CAAC,EAAE,EAAE,QAAQ,KAAK,WAAW,CAAA;AAE9D,qBAAa,WAAW;IACH,EAAE,EAAE,QAAQ;gBAAZ,EAAE,EAAE,QAAQ;IAE/B,MAAM,CAAC,OAAO,SACA,QAAQ;IAGhB,IAAI,CAAC,EACT,MAAM,EACN,KAAU,EACV,KAAK,EACL,QAAQ,GACT,EAAE;QACD,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KACjB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA6BzD,MAAM,CAAC,EACX,IAAI,EACJ,GAAG,EACH,QAAQ,EACR,SAAS,EACT,SAAS,EACT,aAAa,GACd,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC,GAAG;QACvD,SAAS,CAAC,EAAE,IAAI,CAAA;QAChB,SAAS,CAAC,EAAE,IAAI,CAAA;KACjB,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAkBzB,MAAM,CAAC,EACX,IAAI,EACJ,GAAG,EACH,aAAa,GACd,EAAE,IAAI,CACL,UAAU,CAAC,MAAM,CAAC,EAClB,MAAM,GAAG,KAAK,GAAG,eAAe,CACjC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBX,MAAM,CACV,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,CACd,IAAI,CACF,UAAU,CAAC,MAAM,CAAC,EAClB,MAAM,GAAG,UAAU,GAAG,eAAe,GAAG,WAAW,CACpD,CACF,GACA,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAiBxB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3C,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU9C,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IAUrE,aAAa,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC;;;;;IAenC,WAAW,CACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IA0BtC,IAAI,CACR,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,EAC7B,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,UAAU,EAAE,CAAC;CAiBzB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/team/index.ts"],"names":[],"mappings":"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"}
@@ -6,18 +6,36 @@ const xrpc_server_1 = require("@atproto/xrpc-server");
6
6
  const lexicons_1 = require("../lexicon/lexicons");
7
7
  const logger_1 = require("../logger");
8
8
  class TeamService {
9
- constructor(db) {
9
+ constructor(db, appviewAgent, appviewDid, createAuthHeaders) {
10
10
  Object.defineProperty(this, "db", {
11
11
  enumerable: true,
12
12
  configurable: true,
13
13
  writable: true,
14
14
  value: db
15
15
  });
16
+ Object.defineProperty(this, "appviewAgent", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: appviewAgent
21
+ });
22
+ Object.defineProperty(this, "appviewDid", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: appviewDid
27
+ });
28
+ Object.defineProperty(this, "createAuthHeaders", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: createAuthHeaders
33
+ });
16
34
  }
17
- static creator() {
18
- return (db) => new TeamService(db);
35
+ static creator(appviewAgent, appviewDid, createAuthHeaders) {
36
+ return (db) => new TeamService(db, appviewAgent, appviewDid, createAuthHeaders);
19
37
  }
20
- async list({ cursor, limit = 25, roles, disabled, }) {
38
+ async list({ cursor, limit = 25, roles, disabled, q, }) {
21
39
  let builder = this.db.db.selectFrom('member').selectAll();
22
40
  if (cursor) {
23
41
  builder = builder.where('createdAt', '>', new Date(cursor));
@@ -34,6 +52,11 @@ class TeamService {
34
52
  if (disabled !== undefined) {
35
53
  builder = builder.where('disabled', disabled ? 'is' : 'is not', true);
36
54
  }
55
+ if (q) {
56
+ builder = builder.where((qb) => qb
57
+ .orWhere('handle', 'ilike', `%${q}%`)
58
+ .orWhere('displayName', 'ilike', `%${q}%`));
59
+ }
37
60
  const members = await builder
38
61
  .limit(limit)
39
62
  .orderBy('createdAt', 'asc')
@@ -122,12 +145,12 @@ class TeamService {
122
145
  };
123
146
  }
124
147
  // getProfiles() only allows 25 DIDs at a time so we need to query in chunks
125
- async getProfiles(dids, ctx) {
148
+ async getProfiles(dids) {
126
149
  const profiles = new Map();
127
150
  try {
128
- const headers = await ctx.appviewAuth(lexicons_1.ids.AppBskyActorGetProfiles);
151
+ const headers = await this.createAuthHeaders(this.appviewDid, lexicons_1.ids.AppBskyActorGetProfiles);
129
152
  for (const actors of (0, common_1.chunkArray)(dids, 25)) {
130
- const { data } = await ctx.appviewAgent.api.app.bsky.actor.getProfiles({ actors }, headers);
153
+ const { data } = await this.appviewAgent.getProfiles({ actors }, headers);
131
154
  data.profiles.forEach((profile) => {
132
155
  profiles.set(profile.did, profile);
133
156
  });
@@ -138,8 +161,34 @@ class TeamService {
138
161
  }
139
162
  return profiles;
140
163
  }
141
- async view(members, ctx) {
142
- const profiles = await this.getProfiles(members.map(({ did }) => did), ctx);
164
+ async syncMemberProfiles() {
165
+ let lastDid = '';
166
+ // Max 25 profiles can be fetched at a time so let's pull 25 members at a time from the db and update their profile details
167
+ do {
168
+ const members = await this.db.db
169
+ .selectFrom('member')
170
+ .select(['did'])
171
+ .limit(25)
172
+ .if(!!lastDid, (q) => q.where('did', '>', lastDid))
173
+ .orderBy('did', 'asc')
174
+ .execute();
175
+ const dids = members.map((member) => member.did);
176
+ const profiles = await this.getProfiles(dids);
177
+ for (const profile of profiles.values()) {
178
+ await this.db.db
179
+ .updateTable('member')
180
+ .where('did', '=', profile.did)
181
+ .set({
182
+ handle: profile.handle,
183
+ displayName: profile.displayName || null,
184
+ })
185
+ .execute();
186
+ }
187
+ lastDid = dids.at(-1) || '';
188
+ } while (lastDid);
189
+ }
190
+ async view(members) {
191
+ const profiles = await this.getProfiles(members.map(({ did }) => did));
143
192
  return members.map((member) => {
144
193
  return {
145
194
  did: member.did,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/team/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/team/index.ts"],"names":[],"mappings":";;;AAEA,4CAA4C;AAC5C,sDAA0D;AAG1D,kDAAyC;AAGzC,sCAAsC;AAKtC,MAAa,WAAW;IACtB,YACS,EAAY,EACX,YAAsB,EACtB,UAAkB,EAClB,iBAGiB;QANzB;;;;mBAAO,EAAE;WAAU;QACnB;;;;mBAAQ,YAAY;WAAU;QAC9B;;;;mBAAQ,UAAU;WAAQ;QAC1B;;;;mBAAQ,iBAAiB;WAGA;IACxB,CAAC;IAEJ,MAAM,CAAC,OAAO,CACZ,YAAsB,EACtB,UAAkB,EAClB,iBAAwE;QAExE,OAAO,CAAC,EAAY,EAAE,EAAE,CACtB,IAAI,WAAW,CAAC,EAAE,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAA;IACpE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EACT,MAAM,EACN,KAAK,GAAG,EAAE,EACV,KAAK,EACL,QAAQ,EACR,CAAC,GAOF;QACC,IAAI,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,CAAA;QACzD,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;QAC7D,CAAC;QACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAC7B,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,KAAK,iCAAiC;gBACvC,CAAC,KAAK,qCAAqC;gBAC3C,CAAC,KAAK,kCAAkC,CAC3C,CAAA;YAED,yEAAyE;YACzE,IAAI,CAAC,UAAU,CAAC,MAAM;gBAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;YAE9C,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAA;QACnD,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QACvE,CAAC;QACD,IAAI,CAAC,EAAE,CAAC;YACN,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAC7B,EAAE;iBACC,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC;iBACpC,OAAO,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAC7C,CAAA;QACH,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,OAAO;aAC1B,KAAK,CAAC,KAAK,CAAC;aACZ,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC;aAC3B,OAAO,EAAE,CAAA;QAEZ,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,CAAA;IACrE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EACX,IAAI,EACJ,GAAG,EACH,QAAQ,EACR,SAAS,EACT,SAAS,EACT,aAAa,GAId;QACC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QACtB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAC/B,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC;YACN,IAAI;YACJ,GAAG;YACH,QAAQ;YACR,aAAa;YACb,SAAS,EAAE,SAAS,IAAI,GAAG;YAC3B,SAAS,EAAE,SAAS,IAAI,GAAG;SAC5B,CAAC;aACD,YAAY,EAAE;aACd,uBAAuB,EAAE,CAAA;QAE5B,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EACX,IAAI,EACJ,GAAG,EACH,aAAa,GAId;QACC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QACtB,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACb,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC;YACN,IAAI;YACJ,GAAG;YACH,aAAa;YACb,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACf,CAAC;aACD,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CACjB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CACtE;aACA,OAAO,EAAE,CAAA;IACd,CAAC;IAED,KAAK,CAAC,MAAM,CACV,GAAW,EACX,OAKC;QAED,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,GAAG,IAAI,IAAI,EAAE,EAAE,GAAG,OAAO,CAAA;QACzE,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACnC,WAAW,CAAC,QAAQ,CAAC;aACrB,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,GAAG,CAAC;YACH,IAAI;YACJ,QAAQ;YACR,aAAa;YACb,SAAS;SACV,CAAC;aACD,YAAY,EAAE;aACd,uBAAuB,EAAE,CAAA;QAE5B,OAAO,aAAa,CAAA;IACtB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,CAAA;IACxE,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,GAAW;QAC/B,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;QAEpD,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,iCAAmB,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAA;QACrE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,GAAW;QAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAC5B,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,gBAAgB,EAAE,CAAA;QAErB,OAAO,CAAC,CAAC,MAAM,CAAA;IACjB,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,GAAW;QACzB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAC5B,UAAU,CAAC,QAAQ,CAAC;aACpB,SAAS,EAAE;aACX,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,gBAAgB,EAAE,CAAA;QAErB,OAAO,MAAM,CAAA;IACf,CAAC;IAED,aAAa,CAAC,MAA2B;QACvC,MAAM,OAAO,GAAG,MAAM,EAAE,IAAI,KAAK,iCAAiC,CAAA;QAClE,MAAM,WAAW,GACf,OAAO,IAAI,MAAM,EAAE,IAAI,KAAK,qCAAqC,CAAA;QACnE,MAAM,QAAQ,GACZ,WAAW,IAAI,MAAM,EAAE,IAAI,KAAK,kCAAkC,CAAA;QAEpE,OAAO;YACL,WAAW;YACX,OAAO;YACP,QAAQ;SACT,CAAA;IACH,CAAC;IAED,4EAA4E;IAC5E,KAAK,CAAC,WAAW,CAAC,IAAc;QAC9B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA+B,CAAA;QAEvD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAC1C,IAAI,CAAC,UAAU,EACf,cAAG,CAAC,uBAAuB,CAC5B,CAAA;YAED,KAAK,MAAM,MAAM,IAAI,IAAA,mBAAU,EAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;gBAC1C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,CAClD,EAAE,MAAM,EAAE,EACV,OAAO,CACR,CAAA;gBAED,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;oBAChC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;gBACpC,CAAC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,mBAAU,CAAC,KAAK,CACd,EAAE,KAAK,EAAE,IAAI,EAAE,EACf,yCAAyC,CAC1C,CAAA;QACH,CAAC;QAED,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,2HAA2H;QAC3H,GAAG,CAAC;YACF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;iBAC7B,UAAU,CAAC,QAAQ,CAAC;iBACpB,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;iBACf,KAAK,CAAC,EAAE,CAAC;iBACT,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;iBAClD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;iBACrB,OAAO,EAAE,CAAA;YAEZ,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAChD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;YAE7C,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;gBACxC,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;qBACb,WAAW,CAAC,QAAQ,CAAC;qBACrB,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC;qBAC9B,GAAG,CAAC;oBACH,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;iBACzC,CAAC;qBACD,OAAO,EAAE,CAAA;YACd,CAAC;YAED,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QAC7B,CAAC,QAAQ,OAAO,EAAC;IACnB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAA6B;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QACtE,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC5B,OAAO;gBACL,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;gBACjC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE;gBACzC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE;gBACzC,aAAa,EAAE,MAAM,CAAC,aAAa;aACpC,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AA3QD,kCA2QC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/ozone",
3
- "version": "0.1.87",
3
+ "version": "0.1.88",
4
4
  "license": "MIT",
5
5
  "description": "Backend service for moderating the Bluesky network.",
6
6
  "keywords": [
@@ -35,7 +35,7 @@
35
35
  "typed-emitter": "^2.1.0",
36
36
  "uint8arrays": "3.0.0",
37
37
  "undici": "^6.14.1",
38
- "@atproto/api": "^0.14.8",
38
+ "@atproto/api": "^0.14.9",
39
39
  "@atproto/common": "^0.4.8",
40
40
  "@atproto/crypto": "^0.4.4",
41
41
  "@atproto/identity": "^0.4.6",
@@ -55,7 +55,7 @@
55
55
  "ts-node": "^10.8.2",
56
56
  "typescript": "^5.6.3",
57
57
  "@atproto/lex-cli": "^0.6.2",
58
- "@atproto/pds": "^0.4.105"
58
+ "@atproto/pds": "^0.4.106"
59
59
  },
60
60
  "scripts": {
61
61
  "codegen": "lex gen-server --yes ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/* ../../lexicons/chat/bsky/*/* ../../lexicons/tools/ozone/*/*",
@@ -26,14 +26,19 @@ export default function (server: Server, ctx: AppContext) {
26
26
  )
27
27
  }
28
28
 
29
+ const profiles = await teamService.getProfiles([did])
30
+ const profile = profiles.get(did)
31
+
29
32
  const member = await teamService.create({
30
33
  did,
34
+ handle: profile?.handle || null,
35
+ displayName: profile?.displayName || null,
31
36
  disabled: false,
32
37
  role: getMemberRole(role),
33
38
  lastUpdatedBy:
34
39
  access.type === 'admin_token' ? 'admin_token' : access.iss,
35
40
  })
36
- const memberView = await teamService.view([member], ctx)
41
+ const memberView = await teamService.view([member])
37
42
  return memberView[0]
38
43
  })
39
44
 
@@ -12,7 +12,7 @@ export default function (server: Server, ctx: AppContext) {
12
12
  encoding: 'application/json',
13
13
  body: {
14
14
  cursor,
15
- members: await teamService.view(members, ctx),
15
+ members: await teamService.view(members),
16
16
  },
17
17
  }
18
18
  },
@@ -34,7 +34,7 @@ export default function (server: Server, ctx: AppContext) {
34
34
  lastUpdatedBy:
35
35
  access.type === 'admin_token' ? 'admin_token' : access.iss,
36
36
  })
37
- const memberView = await teamService.view([updated], ctx)
37
+ const memberView = await teamService.view([updated])
38
38
  return memberView[0]
39
39
  })
40
40
 
@@ -25,6 +25,7 @@ export const envToCfg = (env: OzoneEnvironment): OzoneConfig => {
25
25
  poolMaxUses: env.dbPoolMaxUses,
26
26
  poolIdleTimeoutMs: env.dbPoolIdleTimeoutMs,
27
27
  materializedViewRefreshIntervalMs: env.dbMaterializedViewRefreshIntervalMs,
28
+ teamProfileRefreshIntervalMs: env.dbTeamProfileRefreshIntervalMs,
28
29
  }
29
30
 
30
31
  assert(env.appviewUrl, 'appviewUrl is required')
@@ -124,6 +125,7 @@ export type DatabaseConfig = {
124
125
  poolMaxUses?: number
125
126
  poolIdleTimeoutMs?: number
126
127
  materializedViewRefreshIntervalMs?: number
128
+ teamProfileRefreshIntervalMs?: number
127
129
  }
128
130
 
129
131
  export type AppviewConfig = {
package/src/config/env.ts CHANGED
@@ -23,6 +23,9 @@ export const readEnv = (): OzoneEnvironment => {
23
23
  dbMaterializedViewRefreshIntervalMs: envInt(
24
24
  'OZONE_DB_MATERIALIZED_VIEW_REFRESH_INTERVAL_MS',
25
25
  ),
26
+ dbTeamProfileRefreshIntervalMs: envInt(
27
+ 'OZONE_DB_TEAM_PROFILE_REFRESH_INTERVAL_MS',
28
+ ),
26
29
  didPlcUrl: envStr('OZONE_DID_PLC_URL'),
27
30
  didCacheStaleTTL: envInt('OZONE_DID_CACHE_STALE_TTL'),
28
31
  didCacheMaxTTL: envInt('OZONE_DID_CACHE_MAX_TTL'),
@@ -57,6 +60,7 @@ export type OzoneEnvironment = {
57
60
  dbPoolMaxUses?: number
58
61
  dbPoolIdleTimeoutMs?: number
59
62
  dbMaterializedViewRefreshIntervalMs?: number
63
+ dbTeamProfileRefreshIntervalMs?: number
60
64
  didPlcUrl?: string
61
65
  didCacheStaleTTL?: number
62
66
  didCacheMaxTTL?: number
package/src/context.ts CHANGED
@@ -120,7 +120,11 @@ export class AppContext {
120
120
  )
121
121
 
122
122
  const communicationTemplateService = CommunicationTemplateService.creator()
123
- const teamService = TeamService.creator()
123
+ const teamService = TeamService.creator(
124
+ appviewAgent,
125
+ cfg.appview.did,
126
+ createAuthHeaders,
127
+ )
124
128
  const setService = SetService.creator()
125
129
  const settingService = SettingService.creator()
126
130
 
@@ -7,10 +7,12 @@ 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 { TeamService } from '../team'
10
11
  import { getSigningKeyId } from '../util'
11
12
  import { EventPusher } from './event-pusher'
12
13
  import { EventReverser } from './event-reverser'
13
14
  import { MaterializedViewRefresher } from './materialized-view-refresher'
15
+ import { TeamProfileSynchronizer } from './team-profile-synchronizer'
14
16
 
15
17
  export type DaemonContextOptions = {
16
18
  db: Database
@@ -20,6 +22,7 @@ export type DaemonContextOptions = {
20
22
  eventPusher: EventPusher
21
23
  eventReverser: EventReverser
22
24
  materializedViewRefresher: MaterializedViewRefresher
25
+ teamProfileSynchronizer: TeamProfileSynchronizer
23
26
  }
24
27
 
25
28
  export class DaemonContext {
@@ -67,6 +70,16 @@ export class DaemonContext {
67
70
  appviewAgent,
68
71
  createAuthHeaders,
69
72
  )
73
+ const teamService = TeamService.creator(
74
+ appviewAgent,
75
+ cfg.appview.did,
76
+ createAuthHeaders,
77
+ )
78
+ const teamProfileSynchronizer = new TeamProfileSynchronizer(
79
+ backgroundQueue,
80
+ teamService(db),
81
+ cfg.db.teamProfileRefreshIntervalMs,
82
+ )
70
83
 
71
84
  const eventReverser = new EventReverser(db, modService)
72
85
 
@@ -83,6 +96,7 @@ export class DaemonContext {
83
96
  eventPusher,
84
97
  eventReverser,
85
98
  materializedViewRefresher,
99
+ teamProfileSynchronizer,
86
100
  ...(overrides ?? {}),
87
101
  })
88
102
  }
@@ -111,16 +125,22 @@ export class DaemonContext {
111
125
  return this.opts.materializedViewRefresher
112
126
  }
113
127
 
128
+ get teamProfileSynchronizer(): TeamProfileSynchronizer {
129
+ return this.opts.teamProfileSynchronizer
130
+ }
131
+
114
132
  async start() {
115
133
  this.eventPusher.start()
116
134
  this.eventReverser.start()
117
135
  this.materializedViewRefresher.start()
136
+ this.teamProfileSynchronizer.start()
118
137
  }
119
138
 
120
139
  async processAll() {
121
140
  // Sequential because the materialized view values depend on the events.
122
141
  await this.eventPusher.processAll()
123
142
  await this.materializedViewRefresher.run()
143
+ await this.teamProfileSynchronizer.run()
124
144
  }
125
145
 
126
146
  async destroy() {
@@ -129,6 +149,7 @@ export class DaemonContext {
129
149
  this.eventReverser.destroy(),
130
150
  this.eventPusher.destroy(),
131
151
  this.materializedViewRefresher.destroy(),
152
+ this.teamProfileSynchronizer.destroy(),
132
153
  ])
133
154
  } finally {
134
155
  await this.backgroundQueue.destroy()
@@ -0,0 +1,15 @@
1
+ import { HOUR } from '@atproto/common'
2
+ import { BackgroundQueue, PeriodicBackgroundTask } from '../background'
3
+ import { TeamService } from '../team'
4
+
5
+ export class TeamProfileSynchronizer extends PeriodicBackgroundTask {
6
+ constructor(
7
+ backgroundQueue: BackgroundQueue,
8
+ teamService: TeamService,
9
+ interval = 24 * HOUR,
10
+ ) {
11
+ super(backgroundQueue, interval, async () => {
12
+ await teamService.syncMemberProfiles()
13
+ })
14
+ }
15
+ }
@@ -0,0 +1,14 @@
1
+ import { Kysely } from 'kysely'
2
+
3
+ export async function up(db: Kysely<unknown>): Promise<void> {
4
+ await db.schema.alterTable('member').addColumn('handle', 'text').execute()
5
+ await db.schema
6
+ .alterTable('member')
7
+ .addColumn('displayName', 'text')
8
+ .execute()
9
+ }
10
+
11
+ export async function down(db: Kysely<unknown>): Promise<void> {
12
+ await db.schema.alterTable('member').dropColumn('handle').execute()
13
+ await db.schema.alterTable('member').dropColumn('displayName').execute()
14
+ }
@@ -21,3 +21,4 @@ export * as _20241220T144630860Z from './20241220T144630860Z-stats-materialized-
21
21
  export * as _20250204T003647759Z from './20250204T003647759Z-add-subject-priority-score'
22
22
  export * as _20250211T003647759Z from './20250211T003647759Z-add-reporter-stats-index'
23
23
  export * as _20250211T132135150Z from './20250211T132135150Z-moderation-event-message-partial-idx'
24
+ export * as _20250221T132135150Z from './20250221T132135150Z-member-details'
@@ -9,6 +9,8 @@ export interface Member {
9
9
  | 'tools.ozone.team.defs#roleTriage'
10
10
  | 'tools.ozone.team.defs#roleModerator'
11
11
  disabled: Generated<boolean>
12
+ handle: string | null
13
+ displayName: string | null
12
14
  createdAt: Date
13
15
  updatedAt: Date
14
16
  lastUpdatedBy: string
@@ -14365,6 +14365,9 @@ export const schemaDict = {
14365
14365
  parameters: {
14366
14366
  type: 'params',
14367
14367
  properties: {
14368
+ q: {
14369
+ type: 'string',
14370
+ },
14368
14371
  disabled: {
14369
14372
  type: 'boolean',
14370
14373
  },
@@ -14,6 +14,7 @@ const is$typed = _is$typed,
14
14
  const id = 'tools.ozone.team.listMembers'
15
15
 
16
16
  export interface QueryParams {
17
+ q?: string
17
18
  disabled?: boolean
18
19
  roles?: string[]
19
20
  limit: number
package/src/team/index.ts CHANGED
@@ -1,21 +1,35 @@
1
1
  import { Selectable } from 'kysely'
2
+ import AtpAgent from '@atproto/api'
2
3
  import { chunkArray } from '@atproto/common'
3
4
  import { InvalidRequestError } from '@atproto/xrpc-server'
4
- import { AppContext } from '../context'
5
5
  import { Database } from '../db'
6
6
  import { Member } from '../db/schema/member'
7
7
  import { ids } from '../lexicon/lexicons'
8
8
  import { ProfileViewDetailed } from '../lexicon/types/app/bsky/actor/defs'
9
9
  import { Member as TeamMember } from '../lexicon/types/tools/ozone/team/defs'
10
10
  import { httpLogger } from '../logger'
11
+ import { AuthHeaders } from '../mod-service/views'
11
12
 
12
13
  export type TeamServiceCreator = (db: Database) => TeamService
13
14
 
14
15
  export class TeamService {
15
- constructor(public db: Database) {}
16
+ constructor(
17
+ public db: Database,
18
+ private appviewAgent: AtpAgent,
19
+ private appviewDid: string,
20
+ private createAuthHeaders: (
21
+ aud: string,
22
+ method: string,
23
+ ) => Promise<AuthHeaders>,
24
+ ) {}
16
25
 
17
- static creator() {
18
- return (db: Database) => new TeamService(db)
26
+ static creator(
27
+ appviewAgent: AtpAgent,
28
+ appviewDid: string,
29
+ createAuthHeaders: (aud: string, method: string) => Promise<AuthHeaders>,
30
+ ) {
31
+ return (db: Database) =>
32
+ new TeamService(db, appviewAgent, appviewDid, createAuthHeaders)
19
33
  }
20
34
 
21
35
  async list({
@@ -23,7 +37,9 @@ export class TeamService {
23
37
  limit = 25,
24
38
  roles,
25
39
  disabled,
40
+ q,
26
41
  }: {
42
+ q?: string
27
43
  cursor?: string
28
44
  limit?: number
29
45
  disabled?: boolean
@@ -49,6 +65,14 @@ export class TeamService {
49
65
  if (disabled !== undefined) {
50
66
  builder = builder.where('disabled', disabled ? 'is' : 'is not', true)
51
67
  }
68
+ if (q) {
69
+ builder = builder.where((qb) =>
70
+ qb
71
+ .orWhere('handle', 'ilike', `%${q}%`)
72
+ .orWhere('displayName', 'ilike', `%${q}%`),
73
+ )
74
+ }
75
+
52
76
  const members = await builder
53
77
  .limit(limit)
54
78
  .orderBy('createdAt', 'asc')
@@ -182,17 +206,17 @@ export class TeamService {
182
206
  }
183
207
 
184
208
  // getProfiles() only allows 25 DIDs at a time so we need to query in chunks
185
- async getProfiles(
186
- dids: string[],
187
- ctx: AppContext,
188
- ): Promise<Map<string, ProfileViewDetailed>> {
209
+ async getProfiles(dids: string[]): Promise<Map<string, ProfileViewDetailed>> {
189
210
  const profiles = new Map<string, ProfileViewDetailed>()
190
211
 
191
212
  try {
192
- const headers = await ctx.appviewAuth(ids.AppBskyActorGetProfiles)
213
+ const headers = await this.createAuthHeaders(
214
+ this.appviewDid,
215
+ ids.AppBskyActorGetProfiles,
216
+ )
193
217
 
194
218
  for (const actors of chunkArray(dids, 25)) {
195
- const { data } = await ctx.appviewAgent.api.app.bsky.actor.getProfiles(
219
+ const { data } = await this.appviewAgent.getProfiles(
196
220
  { actors },
197
221
  headers,
198
222
  )
@@ -211,14 +235,38 @@ export class TeamService {
211
235
  return profiles
212
236
  }
213
237
 
214
- async view(
215
- members: Selectable<Member>[],
216
- ctx: AppContext,
217
- ): Promise<TeamMember[]> {
218
- const profiles = await this.getProfiles(
219
- members.map(({ did }) => did),
220
- ctx,
221
- )
238
+ async syncMemberProfiles(): Promise<void> {
239
+ let lastDid = ''
240
+ // Max 25 profiles can be fetched at a time so let's pull 25 members at a time from the db and update their profile details
241
+ do {
242
+ const members = await this.db.db
243
+ .selectFrom('member')
244
+ .select(['did'])
245
+ .limit(25)
246
+ .if(!!lastDid, (q) => q.where('did', '>', lastDid))
247
+ .orderBy('did', 'asc')
248
+ .execute()
249
+
250
+ const dids = members.map((member) => member.did)
251
+ const profiles = await this.getProfiles(dids)
252
+
253
+ for (const profile of profiles.values()) {
254
+ await this.db.db
255
+ .updateTable('member')
256
+ .where('did', '=', profile.did)
257
+ .set({
258
+ handle: profile.handle,
259
+ displayName: profile.displayName || null,
260
+ })
261
+ .execute()
262
+ }
263
+
264
+ lastDid = dids.at(-1) || ''
265
+ } while (lastDid)
266
+ }
267
+
268
+ async view(members: Selectable<Member>[]): Promise<TeamMember[]> {
269
+ const profiles = await this.getProfiles(members.map(({ did }) => did))
222
270
  return members.map((member) => {
223
271
  return {
224
272
  did: member.did,
@@ -11,6 +11,9 @@ describe('team management', () => {
11
11
  beforeAll(async () => {
12
12
  network = await TestNetwork.create({
13
13
  dbPostgresSchema: 'ozone_team_test',
14
+ ozone: {
15
+ dbTeamProfileRefreshIntervalMs: 100,
16
+ },
14
17
  })
15
18
  adminAgent = network.pds.getClient()
16
19
  sc = network.getSeedClient()
@@ -29,6 +32,7 @@ describe('team management', () => {
29
32
  identifier: sc.accounts[sc.dids.carol].handle,
30
33
  password: sc.accounts[sc.dids.carol].password,
31
34
  })
35
+ await network.processAll()
32
36
  })
33
37
 
34
38
  afterAll(async () => {
@@ -41,6 +45,7 @@ describe('team management', () => {
41
45
  adminAgent.tools.ozone.team.listMembers({}),
42
46
  triageAgent.tools.ozone.team.listMembers({}),
43
47
  ])
48
+
44
49
  expect(forSnapshot(forAdmin.members)).toMatchSnapshot()
45
50
  expect(forSnapshot(forTriage.members)).toMatchSnapshot()
46
51
  // Validate that the list looks the same to both admin and triage members
@@ -89,6 +94,24 @@ describe('team management', () => {
89
94
  onlyEnabled.members.find(({ disabled }) => disabled),
90
95
  ).toBeUndefined()
91
96
  })
97
+ it('allows filtering members by handle/display name', async () => {
98
+ const [{ data: matchingHandle }, { data: matchingName }] =
99
+ await Promise.all([
100
+ adminAgent.tools.ozone.team.listMembers({
101
+ q: 'bob',
102
+ }),
103
+ adminAgent.tools.ozone.team.listMembers({
104
+ q: 'dev',
105
+ }),
106
+ ])
107
+
108
+ expect(matchingHandle.members.length).toEqual(1)
109
+ expect(matchingHandle.members[0]?.profile?.handle).toEqual('bob.test')
110
+ expect(matchingName.members.length).toEqual(1)
111
+ expect(matchingName.members[0]?.profile?.handle).toEqual(
112
+ 'mod-authority.test',
113
+ )
114
+ })
92
115
  })
93
116
 
94
117
  describe('addMember', () => {