@atproto/dev-env 0.3.168 → 0.3.169

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.
@@ -0,0 +1,23 @@
1
+ import { AtpAgent } from '@atproto/api';
2
+ import { TestPds } from './pds';
3
+ export type ServiceUserDetails = {
4
+ email: string;
5
+ handle: string;
6
+ password: string;
7
+ };
8
+ export type ServiceMigrationOptions = {
9
+ services?: Record<string, unknown>;
10
+ verificationMethods?: Record<string, unknown>;
11
+ };
12
+ export declare class ServiceProfile {
13
+ protected pds: TestPds;
14
+ /** @note assumes the session is already authenticated */
15
+ protected client: AtpAgent;
16
+ protected userDetails: ServiceUserDetails;
17
+ protected constructor(pds: TestPds,
18
+ /** @note assumes the session is already authenticated */
19
+ client: AtpAgent, userDetails: ServiceUserDetails);
20
+ get did(): string;
21
+ migrateTo(newPds: TestPds, options?: ServiceMigrationOptions): Promise<void>;
22
+ }
23
+ //# sourceMappingURL=service-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-profile.d.ts","sourceRoot":"","sources":["../src/service-profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9C,CAAA;AAED,qBAAa,cAAc;IAEvB,SAAS,CAAC,GAAG,EAAE,OAAO;IACtB,yDAAyD;IACzD,SAAS,CAAC,MAAM,EAAE,QAAQ;IAC1B,SAAS,CAAC,WAAW,EAAE,kBAAkB;IAJ3C,SAAS,aACG,GAAG,EAAE,OAAO;IACtB,yDAAyD;IAC/C,MAAM,EAAE,QAAQ,EAChB,WAAW,EAAE,kBAAkB;IAG3C,IAAI,GAAG,WAEN;IAEK,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,GAAE,uBAA4B;CAmEvE"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceProfile = void 0;
4
+ class ServiceProfile {
5
+ constructor(pds,
6
+ /** @note assumes the session is already authenticated */
7
+ client, userDetails) {
8
+ Object.defineProperty(this, "pds", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: pds
13
+ });
14
+ Object.defineProperty(this, "client", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: client
19
+ });
20
+ Object.defineProperty(this, "userDetails", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: userDetails
25
+ });
26
+ }
27
+ get did() {
28
+ return this.client.assertDid;
29
+ }
30
+ async migrateTo(newPds, options = {}) {
31
+ const newClient = newPds.getClient();
32
+ const newPdsDesc = await newClient.com.atproto.server.describeServer();
33
+ const serviceAuth = await this.client.com.atproto.server.getServiceAuth({
34
+ aud: newPdsDesc.data.did,
35
+ lxm: 'com.atproto.server.createAccount',
36
+ });
37
+ const inviteCode = newPds.ctx.cfg.invites.required
38
+ ? await newClient.com.atproto.server
39
+ .createInviteCode({ useCount: 1 }, {
40
+ encoding: 'application/json',
41
+ headers: newPds.adminAuthHeaders(),
42
+ })
43
+ .then((res) => res.data.code)
44
+ : undefined;
45
+ await newClient.createAccount({
46
+ ...this.userDetails,
47
+ inviteCode,
48
+ did: this.did,
49
+ }, {
50
+ encoding: 'application/json',
51
+ headers: { authorization: `Bearer ${serviceAuth.data.token}` },
52
+ });
53
+ // The session manager will use the "didDoc" in the result of
54
+ // "createAccount" in order to setup the pdsUrl. However, since are in the
55
+ // process of migrating, that didDoc references the old PDS. In order to
56
+ // avoid calling the old PDS, let's clear the pdsUrl, which will result in
57
+ // the (new) serviceUrl being used.
58
+ newClient.sessionManager.pdsUrl = undefined;
59
+ const newDidCredentialsRes = await newClient.com.atproto.identity.getRecommendedDidCredentials();
60
+ await this.client.com.atproto.identity.requestPlcOperationSignature();
61
+ const { token } = await this.pds.ctx.accountManager.db.db
62
+ .selectFrom('email_token')
63
+ .select('token')
64
+ .where('did', '=', this.did)
65
+ .where('purpose', '=', 'plc_operation')
66
+ .executeTakeFirstOrThrow();
67
+ const op = { ...newDidCredentialsRes.data, token };
68
+ Object.assign((op.services ?? (op.services = {})), options.services);
69
+ Object.assign((op.verificationMethods ?? (op.verificationMethods = {})), options.verificationMethods);
70
+ const signedPlcOperation = await this.client.com.atproto.identity.signPlcOperation(op);
71
+ await newClient.com.atproto.identity.submitPlcOperation({
72
+ operation: signedPlcOperation.data.operation,
73
+ });
74
+ await newClient.com.atproto.server.activateAccount();
75
+ this.pds = newPds;
76
+ this.client = newClient;
77
+ }
78
+ }
79
+ exports.ServiceProfile = ServiceProfile;
80
+ //# sourceMappingURL=service-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-profile.js","sourceRoot":"","sources":["../src/service-profile.ts"],"names":[],"mappings":";;;AAcA,MAAa,cAAc;IACzB,YACY,GAAY;IACtB,yDAAyD;IAC/C,MAAgB,EAChB,WAA+B;QAHzC;;;;mBAAU,GAAG;WAAS;QAEtB;;;;mBAAU,MAAM;WAAU;QAC1B;;;;mBAAU,WAAW;WAAoB;IACxC,CAAC;IAEJ,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,MAAe,EAAE,UAAmC,EAAE;QACpE,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,EAAE,CAAA;QAEpC,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;QACtE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;YACtE,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG;YACxB,GAAG,EAAE,kCAAkC;SACxC,CAAC,CAAA;QAEF,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ;YAChD,CAAC,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM;iBAC/B,gBAAgB,CACf,EAAE,QAAQ,EAAE,CAAC,EAAE,EACf;gBACE,QAAQ,EAAE,kBAAkB;gBAC5B,OAAO,EAAE,MAAM,CAAC,gBAAgB,EAAE;aACnC,CACF;iBACA,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YACjC,CAAC,CAAC,SAAS,CAAA;QAEb,MAAM,SAAS,CAAC,aAAa,CAC3B;YACE,GAAG,IAAI,CAAC,WAAW;YACnB,UAAU;YACV,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,EACD;YACE,QAAQ,EAAE,kBAAkB;YAC5B,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE;SAC/D,CACF,CAAA;QAED,6DAA6D;QAC7D,0EAA0E;QAC1E,wEAAwE;QACxE,0EAA0E;QAC1E,mCAAmC;QACnC,SAAS,CAAC,cAAc,CAAC,MAAM,GAAG,SAAS,CAAA;QAE3C,MAAM,oBAAoB,GACxB,MAAM,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,4BAA4B,EAAE,CAAA;QAErE,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,4BAA4B,EAAE,CAAA;QACrE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE;aACtD,UAAU,CAAC,aAAa,CAAC;aACzB,MAAM,CAAC,OAAO,CAAC;aACf,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;aAC3B,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,eAAe,CAAC;aACtC,uBAAuB,EAAE,CAAA;QAE5B,MAAM,EAAE,GAAG,EAAE,GAAG,oBAAoB,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA;QAClD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,KAAX,EAAE,CAAC,QAAQ,GAAK,EAAE,EAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;QACrD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,mBAAmB,KAAtB,EAAE,CAAC,mBAAmB,GAAK,EAAE,EAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAA;QAE3E,MAAM,kBAAkB,GACtB,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAA;QAE7D,MAAM,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;YACtD,SAAS,EAAE,kBAAkB,CAAC,IAAI,CAAC,SAAS;SAC7C,CAAC,CAAA;QAEF,MAAM,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,CAAA;QAEpD,IAAI,CAAC,GAAG,GAAG,MAAM,CAAA;QACjB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAA;IACzB,CAAC;CACF;AA/ED,wCA+EC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/dev-env",
3
- "version": "0.3.168",
3
+ "version": "0.3.169",
4
4
  "license": "MIT",
5
5
  "description": "Local development environment helper for atproto development",
6
6
  "keywords": [
@@ -27,18 +27,18 @@
27
27
  "multiformats": "^9.9.0",
28
28
  "uint8arrays": "3.0.0",
29
29
  "undici": "^6.14.1",
30
- "@atproto/api": "^0.16.5",
31
- "@atproto/bsky": "^0.0.180",
32
- "@atproto/bsync": "^0.0.20",
30
+ "@atproto/api": "^0.16.6",
31
+ "@atproto/bsky": "^0.0.181",
32
+ "@atproto/bsync": "^0.0.21",
33
33
  "@atproto/common-web": "^0.4.2",
34
34
  "@atproto/crypto": "^0.4.4",
35
35
  "@atproto/identity": "^0.4.8",
36
- "@atproto/lexicon": "^0.4.14",
37
- "@atproto/ozone": "^0.1.138",
38
- "@atproto/pds": "^0.4.172",
39
- "@atproto/sync": "^0.1.32",
40
- "@atproto/syntax": "^0.4.0",
41
- "@atproto/xrpc-server": "^0.9.3"
36
+ "@atproto/lexicon": "^0.5.0",
37
+ "@atproto/ozone": "^0.1.139",
38
+ "@atproto/pds": "^0.4.173",
39
+ "@atproto/sync": "^0.1.33",
40
+ "@atproto/syntax": "^0.4.1",
41
+ "@atproto/xrpc-server": "^0.9.4"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/express": "^4.17.13",
package/src/bin.ts CHANGED
@@ -39,21 +39,20 @@ const run = async () => {
39
39
 
40
40
  if (network.introspect) {
41
41
  console.log(
42
- `🔍 Dev-env introspection server started http://localhost:${network.introspect.port}`,
42
+ `🔍 Dev-env introspection server http://localhost:${network.introspect.port}`,
43
43
  )
44
44
  }
45
+ console.log(`👤 DID Placeholder server http://localhost:${network.plc.port}`)
46
+ console.log(`🌞 Main PDS http://localhost:${network.pds.port}`)
45
47
  console.log(
46
- `👤 DID Placeholder server started http://localhost:${network.plc.port}`,
48
+ `🔨 Lexicon authority DID ${network.pds.ctx.cfg.lexicon.didAuthority}`,
47
49
  )
48
- console.log(
49
- `🌞 Personal Data server started http://localhost:${network.pds.port}`,
50
- )
51
- console.log(`🗼 Ozone server started http://localhost:${network.ozone.port}`)
50
+ console.log(`🗼 Ozone server http://localhost:${network.ozone.port}`)
52
51
  console.log(`🗼 Ozone service DID ${network.ozone.ctx.cfg.service.did}`)
53
- console.log(`🌅 Bsky Appview started http://localhost:${network.bsky.port}`)
52
+ console.log(`🌅 Bsky Appview http://localhost:${network.bsky.port}`)
54
53
  console.log(`🌅 Bsky Appview DID ${network.bsky.serverDid}`)
55
54
  for (const fg of network.feedGens) {
56
- console.log(`🤖 Feed Generator started http://localhost:${fg.port}`)
55
+ console.log(`🤖 Feed Generator (${fg.did}) http://localhost:${fg.port}`)
57
56
  }
58
57
  }
59
58
 
package/src/mock/index.ts CHANGED
@@ -542,6 +542,7 @@ export async function generateMockSetup(env: TestNetwork) {
542
542
 
543
543
  await setVerifier(env.bsky.db, alice.accountDid)
544
544
 
545
+ // @TODO the following should be optimized as it makes dev-env start very slow (>10 sec)
545
546
  const sc = env.getSeedClient()
546
547
  await seedThreadV2.simple(sc)
547
548
  await seedThreadV2.long(sc)
package/src/network.ts CHANGED
@@ -8,9 +8,10 @@ import { EXAMPLE_LABELER } from './const'
8
8
  import { IntrospectServer } from './introspect'
9
9
  import { TestNetworkNoAppView } from './network-no-appview'
10
10
  import { TestOzone } from './ozone'
11
- import { OzoneServiceProfile } from './ozone-service-profile'
12
11
  import { TestPds } from './pds'
13
12
  import { TestPlc } from './plc'
13
+ import { LexiconAuthorityProfile } from './service-profile-lexicon'
14
+ import { OzoneServiceProfile } from './service-profile-ozone'
14
15
  import { TestServerParams } from './types'
15
16
  import { mockNetworkUtilities } from './util'
16
17
 
@@ -44,16 +45,23 @@ export class TestNetwork extends TestNetworkNoAppView {
44
45
  const pdsPort = params.pds?.port ?? (await getPort())
45
46
  const ozonePort = params.ozone?.port ?? (await getPort())
46
47
 
47
- const thirdPartyPdsProps = {
48
+ const thirdPartyPds = await TestPds.create({
48
49
  didPlcUrl: plc.url,
49
50
  ...params.pds,
50
51
  inviteRequired: false,
51
52
  port: await getPort(),
52
- }
53
- const thirdPartyPds = await TestPds.create(thirdPartyPdsProps)
54
- const ozoneServiceProfile = new OzoneServiceProfile(thirdPartyPds)
55
- const { did: ozoneDid, key: ozoneKey } =
56
- await ozoneServiceProfile.createDidAndKey()
53
+ })
54
+
55
+ const ozoneUrl = `http://localhost:${ozonePort}`
56
+
57
+ // @TODO (?) rework the ServiceProfile to live on a separate PDS instead of
58
+ // requiring to migrate to the main PDS
59
+ const ozoneServiceProfile = await OzoneServiceProfile.create(
60
+ thirdPartyPds,
61
+ ozoneUrl,
62
+ )
63
+ const lexiconAuthorityProfile =
64
+ await LexiconAuthorityProfile.create(thirdPartyPds)
57
65
 
58
66
  const bsky = await TestBsky.create({
59
67
  port: bskyPort,
@@ -63,29 +71,27 @@ export class TestNetwork extends TestNetworkNoAppView {
63
71
  dbPostgresSchema: `appview_${dbPostgresSchema}`,
64
72
  dbPostgresUrl,
65
73
  redisHost,
66
- modServiceDid: ozoneDid,
67
- labelsFromIssuerDids: [ozoneDid, EXAMPLE_LABELER],
74
+ modServiceDid: ozoneServiceProfile.did,
75
+ labelsFromIssuerDids: [ozoneServiceProfile.did, EXAMPLE_LABELER],
68
76
  ...params.bsky,
69
77
  })
70
78
 
71
- const modServiceUrl = `http://localhost:${ozonePort}`
72
- const pdsProps = {
79
+ const pds = await TestPds.create({
73
80
  port: pdsPort,
74
81
  didPlcUrl: plc.url,
75
82
  bskyAppViewUrl: bsky.url,
76
83
  bskyAppViewDid: bsky.ctx.cfg.serverDid,
77
- modServiceUrl,
78
- modServiceDid: ozoneDid,
84
+ modServiceUrl: ozoneUrl,
85
+ modServiceDid: ozoneServiceProfile.did,
86
+ lexiconDidAuthority: lexiconAuthorityProfile.did,
79
87
  ...params.pds,
80
- }
81
-
82
- const pds = await TestPds.create(pdsProps)
88
+ })
83
89
 
84
90
  const ozone = await TestOzone.create({
85
91
  port: ozonePort,
86
92
  plcUrl: plc.url,
87
- signingKey: ozoneKey,
88
- serverDid: ozoneDid,
93
+ signingKey: ozoneServiceProfile.key,
94
+ serverDid: ozoneServiceProfile.did,
89
95
  dbPostgresSchema: `ozone_${dbPostgresSchema || 'db'}`,
90
96
  dbPostgresUrl,
91
97
  appviewUrl: bsky.url,
@@ -93,39 +99,30 @@ export class TestNetwork extends TestNetworkNoAppView {
93
99
  appviewPushEvents: true,
94
100
  pdsUrl: pds.url,
95
101
  pdsDid: pds.ctx.cfg.service.did,
96
- verifierDid: ozoneDid,
102
+ verifierDid: ozoneServiceProfile.did,
97
103
  verifierUrl: pds.url,
98
104
  verifierPassword: 'temp',
99
105
  ...params.ozone,
100
106
  })
101
107
 
102
- let inviteCode: string | undefined
103
- if (pdsProps.inviteRequired) {
104
- const { data: invite } = await pds
105
- .getClient()
106
- .com.atproto.server.createInviteCode(
107
- { useCount: 1 },
108
- {
109
- encoding: 'application/json',
110
- headers: pds.adminAuthHeaders(),
111
- },
112
- )
113
- inviteCode = invite.code
114
- }
115
- await ozoneServiceProfile.createServiceDetails(pds, modServiceUrl, {
116
- inviteCode,
117
- })
108
+ await ozoneServiceProfile.migrateTo(pds)
109
+ await ozoneServiceProfile.createRecords()
110
+
111
+ await lexiconAuthorityProfile.migrateTo(pds)
112
+ await lexiconAuthorityProfile.createRecords()
118
113
 
119
- await ozone.addAdminDid(ozoneDid)
114
+ await ozone.addAdminDid(ozoneServiceProfile.did)
120
115
 
121
116
  mockNetworkUtilities(pds, bsky)
117
+ await thirdPartyPds.processAll()
122
118
  await pds.processAll()
119
+ await ozone.processAll()
123
120
  await bsky.sub.processAll()
124
121
  await thirdPartyPds.close()
125
122
 
126
123
  // Weird but if we do this before pds.processAll() somehow appview loses this user and tests in different parts fail because appview doesn't return this user in various contexts anymore
127
124
  const ozoneVerifierPassword =
128
- await ozoneServiceProfile.createAppPasswordForVerification(pds)
125
+ await ozoneServiceProfile.createAppPasswordForVerification()
129
126
  if (ozone.daemon.ctx.cfg.verifier) {
130
127
  ozone.daemon.ctx.cfg.verifier.password = ozoneVerifierPassword
131
128
  }
@@ -0,0 +1,104 @@
1
+ import { LexiconDoc } from '@atproto/lexicon'
2
+ import { TestPds } from './pds'
3
+ import { ServiceProfile } from './service-profile'
4
+
5
+ const LEXICONS: readonly LexiconDoc[] = [
6
+ {
7
+ lexicon: 1,
8
+ id: 'com.atproto.moderation.basePermissions',
9
+ defs: {
10
+ main: {
11
+ type: 'permission-set',
12
+ title: 'Moderation',
13
+ 'title:lang': { fr: 'Modération' },
14
+ detail: 'Create moderation reports',
15
+ 'detail:lang': {
16
+ 'fr-FR': 'Créer des rapports de modération',
17
+ },
18
+ permissions: [
19
+ {
20
+ type: 'permission',
21
+ resource: 'rpc',
22
+ aud: '*',
23
+ lxm: ['com.atproto.moderation.createReport'],
24
+ },
25
+ ],
26
+ },
27
+ },
28
+ },
29
+ {
30
+ lexicon: 1,
31
+ id: 'com.example.calendar.basePermissions',
32
+ defs: {
33
+ main: {
34
+ type: 'permission-set',
35
+ title: 'Calendar',
36
+ 'title:lang': { fr: 'Calendrier' },
37
+ detail: 'Manage your events and RSVPs',
38
+ 'detail:lang': {
39
+ 'fr-BE': 'Gérer vos événements et réponses',
40
+ },
41
+ permissions: [
42
+ {
43
+ type: 'permission',
44
+ resource: 'rpc',
45
+ inheritAud: true,
46
+ lxm: [
47
+ 'com.example.calendar.listEvents',
48
+ 'com.example.calendar.getEventDetails',
49
+ 'com.example.calendar.getEventRsvps',
50
+ ],
51
+ },
52
+ {
53
+ type: 'permission',
54
+ resource: 'repo',
55
+ collection: [
56
+ 'com.example.calendar.event',
57
+ 'com.example.calendar.rsvp',
58
+ ],
59
+ },
60
+ {
61
+ type: 'permission',
62
+ resource: 'blob',
63
+ accept: ['image/*', 'video/*'],
64
+ },
65
+ ],
66
+ },
67
+ },
68
+ },
69
+ ]
70
+
71
+ export class LexiconAuthorityProfile extends ServiceProfile {
72
+ public static async create(
73
+ pds: TestPds,
74
+ userDetails = {
75
+ email: 'lex-authority@test.com',
76
+ handle: 'lex-authority.test',
77
+ password: 'hunter2',
78
+ },
79
+ ) {
80
+ const client = pds.getClient()
81
+ await client.createAccount(userDetails)
82
+
83
+ return new LexiconAuthorityProfile(pds, client, userDetails)
84
+ }
85
+
86
+ async createRecords() {
87
+ await this.client.app.bsky.actor.profile.create(
88
+ { repo: this.did },
89
+ {
90
+ displayName: 'Lexicon Authority',
91
+ description: `the repo containing all the lexicons that can be resolved in dev`,
92
+ },
93
+ )
94
+
95
+ for (const doc of LEXICONS) {
96
+ await this.client.com.atproto.repo.createRecord({
97
+ repo: this.did,
98
+ collection: 'com.atproto.lexicon.schema',
99
+ rkey: doc.id,
100
+ record: doc,
101
+ })
102
+ }
103
+ }
104
+ }
@@ -1,116 +1,66 @@
1
1
  import { AtpAgent } from '@atproto/api'
2
2
  import { Secp256k1Keypair } from '@atproto/crypto'
3
3
  import { TestPds } from './pds'
4
+ import {
5
+ ServiceMigrationOptions,
6
+ ServiceProfile,
7
+ ServiceUserDetails,
8
+ } from './service-profile'
4
9
 
5
- export class OzoneServiceProfile {
6
- did?: string
7
- key?: Secp256k1Keypair
8
- thirdPartyPdsClient: AtpAgent
10
+ export class OzoneServiceProfile extends ServiceProfile {
11
+ static async create(
12
+ pds: TestPds,
13
+ ozoneUrl: string,
14
+ userDetails = {
15
+ email: 'mod-authority@test.com',
16
+ handle: 'mod-authority.test',
17
+ password: 'hunter2',
18
+ },
19
+ ) {
20
+ const client = pds.getClient()
21
+ await client.createAccount(userDetails)
9
22
 
10
- modUserDetails = {
11
- email: 'mod-authority@test.com',
12
- handle: 'mod-authority.test',
13
- password: 'hunter2',
14
- }
23
+ const key = await Secp256k1Keypair.create({ exportable: true })
15
24
 
16
- public constructor(public thirdPartyPds: TestPds) {
17
- this.thirdPartyPdsClient = this.thirdPartyPds.getClient()
25
+ return new OzoneServiceProfile(pds, client, userDetails, ozoneUrl, key)
18
26
  }
19
27
 
20
- async createDidAndKey() {
21
- await this.thirdPartyPdsClient.createAccount(this.modUserDetails)
22
-
23
- this.did = this.thirdPartyPdsClient.accountDid
24
- this.key = await Secp256k1Keypair.create({ exportable: true })
25
- return { did: this.did, key: this.key }
28
+ protected constructor(
29
+ pds: TestPds,
30
+ client: AtpAgent,
31
+ userDetails: ServiceUserDetails,
32
+ readonly ozoneUrl: string,
33
+ readonly key: Secp256k1Keypair,
34
+ ) {
35
+ super(pds, client, userDetails)
26
36
  }
27
37
 
28
- async createAppPasswordForVerification(pds: TestPds) {
29
- const pdsClient = pds.getClient()
30
- await pdsClient.login({
31
- identifier: this.modUserDetails.handle,
32
- password: this.modUserDetails.password,
33
- })
34
- const { data } = await pdsClient.com.atproto.server.createAppPassword({
38
+ async createAppPasswordForVerification() {
39
+ const { data } = await this.client.com.atproto.server.createAppPassword({
35
40
  name: 'ozone-verifier',
36
41
  })
37
42
  return data.password
38
43
  }
39
44
 
40
- async createServiceDetails(
41
- pds: TestPds,
42
- ozoneUrl: string,
43
- userDetails: { inviteCode?: string } = {},
44
- ) {
45
- if (!this.did || !this.key) {
46
- throw new Error('No DID/key found!')
47
- }
48
- const pdsClient = pds.getClient()
49
- const describeRes = await pdsClient.com.atproto.server.describeServer()
50
- const newServerDid = describeRes.data.did
51
-
52
- const serviceJwtRes =
53
- await this.thirdPartyPdsClient.com.atproto.server.getServiceAuth({
54
- aud: newServerDid,
55
- lxm: 'com.atproto.server.createAccount',
56
- })
57
- const serviceJwt = serviceJwtRes.data.token
58
-
59
- await pdsClient.createAccount(
60
- {
61
- ...this.modUserDetails,
62
- ...userDetails,
63
- did: this.did,
45
+ async migrateTo(pds: TestPds, options: ServiceMigrationOptions = {}) {
46
+ await super.migrateTo(pds, {
47
+ ...options,
48
+ services: {
49
+ ...options.services,
50
+ atproto_labeler: {
51
+ type: 'AtprotoLabeler',
52
+ endpoint: this.ozoneUrl,
53
+ },
64
54
  },
65
- {
66
- headers: { authorization: `Bearer ${serviceJwt}` },
67
- encoding: 'application/json',
55
+ verificationMethods: {
56
+ ...options.verificationMethods,
57
+ atproto_label: this.key.did(),
68
58
  },
69
- )
70
-
71
- // For some reason, the tests fail if the client uses the PDS URL to make
72
- // its requests. This is a workaround to make the tests pass by simulating
73
- // old behavior (that was not relying on the session management).
74
- pdsClient.sessionManager.pdsUrl = undefined
75
-
76
- const getDidCredentials =
77
- await pdsClient.com.atproto.identity.getRecommendedDidCredentials()
78
-
79
- await this.thirdPartyPdsClient.com.atproto.identity.requestPlcOperationSignature()
80
-
81
- const tokenRes = await this.thirdPartyPds.ctx.accountManager.db.db
82
- .selectFrom('email_token')
83
- .selectAll()
84
- .where('did', '=', this.did)
85
- .where('purpose', '=', 'plc_operation')
86
- .executeTakeFirst()
87
- const token = tokenRes?.token
88
- const plcOperationData = {
89
- token,
90
- ...getDidCredentials.data,
91
- }
92
-
93
- if (!plcOperationData.services) plcOperationData.services = {}
94
- plcOperationData.services['atproto_labeler'] = {
95
- type: 'AtprotoLabeler',
96
- endpoint: ozoneUrl,
97
- }
98
- if (!plcOperationData.verificationMethods)
99
- plcOperationData.verificationMethods = {}
100
- plcOperationData.verificationMethods['atproto_label'] = this.key.did()
101
-
102
- const plcOp =
103
- await this.thirdPartyPdsClient.com.atproto.identity.signPlcOperation(
104
- plcOperationData,
105
- )
106
-
107
- await pdsClient.com.atproto.identity.submitPlcOperation({
108
- operation: plcOp.data.operation,
109
59
  })
60
+ }
110
61
 
111
- await pdsClient.com.atproto.server.activateAccount()
112
-
113
- await pdsClient.app.bsky.actor.profile.create(
62
+ async createRecords() {
63
+ await this.client.app.bsky.actor.profile.create(
114
64
  { repo: this.did },
115
65
  {
116
66
  displayName: 'Dev-env Moderation',
@@ -118,7 +68,7 @@ export class OzoneServiceProfile {
118
68
  },
119
69
  )
120
70
 
121
- await pdsClient.app.bsky.labeler.service.create(
71
+ await this.client.app.bsky.labeler.service.create(
122
72
  { repo: this.did, rkey: 'self' },
123
73
  {
124
74
  policies: {