@atproto/dev-env 0.0.0-spaces-alpha-20260818163953
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.
- package/CHANGELOG.md +3424 -0
- package/LICENSE.txt +7 -0
- package/README.md +39 -0
- package/bin.js +7 -0
- package/dist/bin-multi-pds.d.ts +2 -0
- package/dist/bin-multi-pds.d.ts.map +1 -0
- package/dist/bin-multi-pds.js +130 -0
- package/dist/bin-multi-pds.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +56 -0
- package/dist/bin.js.map +1 -0
- package/dist/bsky.d.ts +27 -0
- package/dist/bsky.d.ts.map +1 -0
- package/dist/bsky.js +165 -0
- package/dist/bsky.js.map +1 -0
- package/dist/bsync.d.ts +22 -0
- package/dist/bsync.d.ts.map +1 -0
- package/dist/bsync.js +54 -0
- package/dist/bsync.js.map +1 -0
- package/dist/const.d.ts +4 -0
- package/dist/const.d.ts.map +1 -0
- package/dist/const.js +4 -0
- package/dist/const.js.map +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +10 -0
- package/dist/env.js.map +1 -0
- package/dist/feed-gen.d.ts +15 -0
- package/dist/feed-gen.d.ts.map +1 -0
- package/dist/feed-gen.js +73 -0
- package/dist/feed-gen.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/introspect.d.ts +22 -0
- package/dist/introspect.d.ts.map +1 -0
- package/dist/introspect.js +65 -0
- package/dist/introspect.js.map +1 -0
- package/dist/mock/data.d.ts +3 -0
- package/dist/mock/data.d.ts.map +1 -0
- package/dist/mock/data.js +46 -0
- package/dist/mock/data.js.map +1 -0
- package/dist/mock/img/blur-hash-avatar-b64.d.ts +3 -0
- package/dist/mock/img/blur-hash-avatar-b64.d.ts.map +1 -0
- package/dist/mock/img/blur-hash-avatar-b64.js +2 -0
- package/dist/mock/img/blur-hash-avatar-b64.js.map +1 -0
- package/dist/mock/img/labeled-img-b64.d.ts +3 -0
- package/dist/mock/img/labeled-img-b64.d.ts.map +1 -0
- package/dist/mock/img/labeled-img-b64.js +2 -0
- package/dist/mock/img/labeled-img-b64.js.map +1 -0
- package/dist/mock/index.d.ts +3 -0
- package/dist/mock/index.d.ts.map +1 -0
- package/dist/mock/index.js +574 -0
- package/dist/mock/index.js.map +1 -0
- package/dist/moderator-client.d.ts +58 -0
- package/dist/moderator-client.d.ts.map +1 -0
- package/dist/moderator-client.js +110 -0
- package/dist/moderator-client.js.map +1 -0
- package/dist/network-no-appview.d.ts +21 -0
- package/dist/network-no-appview.d.ts.map +1 -0
- package/dist/network-no-appview.js +74 -0
- package/dist/network-no-appview.js.map +1 -0
- package/dist/network.d.ts +32 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +190 -0
- package/dist/network.js.map +1 -0
- package/dist/ozone.d.ts +31 -0
- package/dist/ozone.d.ts.map +1 -0
- package/dist/ozone.js +254 -0
- package/dist/ozone.js.map +1 -0
- package/dist/pds.d.ts +23 -0
- package/dist/pds.d.ts.map +1 -0
- package/dist/pds.js +97 -0
- package/dist/pds.js.map +1 -0
- package/dist/plc.d.ts +14 -0
- package/dist/plc.d.ts.map +1 -0
- package/dist/plc.js +28 -0
- package/dist/plc.js.map +1 -0
- package/dist/seed/author-feed.d.ts +4 -0
- package/dist/seed/author-feed.d.ts.map +1 -0
- package/dist/seed/author-feed.js +50 -0
- package/dist/seed/author-feed.js.map +1 -0
- package/dist/seed/basic.d.ts +16 -0
- package/dist/seed/basic.d.ts.map +1 -0
- package/dist/seed/basic.js +113 -0
- package/dist/seed/basic.js.map +1 -0
- package/dist/seed/client.d.ts +151 -0
- package/dist/seed/client.d.ts.map +1 -0
- package/dist/seed/client.js +365 -0
- package/dist/seed/client.js.map +1 -0
- package/dist/seed/follows.d.ts +4 -0
- package/dist/seed/follows.d.ts.map +1 -0
- package/dist/seed/follows.js +55 -0
- package/dist/seed/follows.js.map +1 -0
- package/dist/seed/index.d.ts +11 -0
- package/dist/seed/index.d.ts.map +1 -0
- package/dist/seed/index.js +11 -0
- package/dist/seed/index.js.map +1 -0
- package/dist/seed/likes.d.ts +4 -0
- package/dist/seed/likes.d.ts.map +1 -0
- package/dist/seed/likes.js +37 -0
- package/dist/seed/likes.js.map +1 -0
- package/dist/seed/quotes.d.ts +4 -0
- package/dist/seed/quotes.d.ts.map +1 -0
- package/dist/seed/quotes.js +21 -0
- package/dist/seed/quotes.js.map +1 -0
- package/dist/seed/reposts.d.ts +4 -0
- package/dist/seed/reposts.d.ts.map +1 -0
- package/dist/seed/reposts.js +17 -0
- package/dist/seed/reposts.js.map +1 -0
- package/dist/seed/thread-v2.d.ts +227 -0
- package/dist/seed/thread-v2.d.ts.map +1 -0
- package/dist/seed/thread-v2.js +755 -0
- package/dist/seed/thread-v2.js.map +1 -0
- package/dist/seed/users-bulk.d.ts +3 -0
- package/dist/seed/users-bulk.d.ts.map +1 -0
- package/dist/seed/users-bulk.js +224 -0
- package/dist/seed/users-bulk.js.map +1 -0
- package/dist/seed/users.d.ts +3 -0
- package/dist/seed/users.d.ts.map +1 -0
- package/dist/seed/users.js +45 -0
- package/dist/seed/users.js.map +1 -0
- package/dist/seed/verifications.d.ts +5 -0
- package/dist/seed/verifications.d.ts.map +1 -0
- package/dist/seed/verifications.js +164 -0
- package/dist/seed/verifications.js.map +1 -0
- package/dist/service-profile-lexicon.d.ts +11 -0
- package/dist/service-profile-lexicon.d.ts.map +1 -0
- package/dist/service-profile-lexicon.js +115 -0
- package/dist/service-profile-lexicon.js.map +1 -0
- package/dist/service-profile-ozone.d.ts +18 -0
- package/dist/service-profile-ozone.d.ts.map +1 -0
- package/dist/service-profile-ozone.js +333 -0
- package/dist/service-profile-ozone.js.map +1 -0
- package/dist/service-profile.d.ts +24 -0
- package/dist/service-profile.d.ts.map +1 -0
- package/dist/service-profile.js +61 -0
- package/dist/service-profile.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +14 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +86 -0
- package/dist/util.js.map +1 -0
- package/package.json +69 -0
- package/src/bin-multi-pds.ts +166 -0
- package/src/bin.ts +64 -0
- package/src/bsky.ts +198 -0
- package/src/bsync.ts +66 -0
- package/src/const.ts +3 -0
- package/src/env.ts +9 -0
- package/src/feed-gen.ts +96 -0
- package/src/index.ts +17 -0
- package/src/introspect.ts +91 -0
- package/src/mock/data.ts +46 -0
- package/src/mock/img/blur-hash-avatar-b64.ts +1 -0
- package/src/mock/img/labeled-img-b64.ts +1 -0
- package/src/mock/index.ts +702 -0
- package/src/moderator-client.ts +267 -0
- package/src/network-no-appview.ts +89 -0
- package/src/network.ts +243 -0
- package/src/ozone.ts +287 -0
- package/src/pds.ts +118 -0
- package/src/plc.ts +33 -0
- package/src/seed/author-feed.ts +98 -0
- package/src/seed/basic.ts +189 -0
- package/src/seed/client.ts +676 -0
- package/src/seed/follows.ts +57 -0
- package/src/seed/index.ts +11 -0
- package/src/seed/likes.ts +43 -0
- package/src/seed/quotes.ts +53 -0
- package/src/seed/reposts.ts +18 -0
- package/src/seed/thread-v2.ts +925 -0
- package/src/seed/users-bulk.ts +229 -0
- package/src/seed/users.ts +64 -0
- package/src/seed/verifications.ts +254 -0
- package/src/service-profile-lexicon.ts +127 -0
- package/src/service-profile-ozone.ts +375 -0
- package/src/service-profile.ts +95 -0
- package/src/types.ts +68 -0
- package/src/util.ts +118 -0
- package/tsconfig.build.json +25 -0
- package/tsconfig.json +4 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Dual MIT/Apache-2.0 License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022-2026 Bluesky Social PBC, and Contributors
|
|
4
|
+
|
|
5
|
+
Except as otherwise noted in individual files, this software is licensed under the MIT license (<http://opensource.org/licenses/MIT>), or the Apache License, Version 2.0 (<http://www.apache.org/licenses/LICENSE-2.0>).
|
|
6
|
+
|
|
7
|
+
Downstream projects and end users may chose either license individually, or both together, at their discretion. The motivation for this dual-licensing is the additional software patent assurance provided by Apache 2.0.
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @atproto/dev-env: Local Developer Environment
|
|
2
|
+
|
|
3
|
+
A command-line application for developers to construct and manage development environments.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@atproto/dev-env)
|
|
6
|
+
[](https://github.com/bluesky-social/atproto/actions/workflows/repo.yaml)
|
|
7
|
+
|
|
8
|
+
## REPL API
|
|
9
|
+
|
|
10
|
+
The following methods are available in the REPL.
|
|
11
|
+
|
|
12
|
+
### `status()`
|
|
13
|
+
|
|
14
|
+
List the currently active servers.
|
|
15
|
+
|
|
16
|
+
### `startPds(port?: number)`
|
|
17
|
+
|
|
18
|
+
Create a new PDS instance. Data is stored in memory.
|
|
19
|
+
|
|
20
|
+
### `stop(port: number)`
|
|
21
|
+
|
|
22
|
+
Stop the server at the given port.
|
|
23
|
+
|
|
24
|
+
### `mkuser(handle: string, pdsPort?: number)`
|
|
25
|
+
|
|
26
|
+
Create a new user.
|
|
27
|
+
|
|
28
|
+
### `user(handle: string): ServiceClient`
|
|
29
|
+
|
|
30
|
+
Get the `ServiceClient` for the given user.
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
This project is dual-licensed under MIT and Apache 2.0 terms:
|
|
35
|
+
|
|
36
|
+
- MIT license ([LICENSE-MIT.txt](https://github.com/bluesky-social/atproto/blob/main/LICENSE-MIT.txt) or http://opensource.org/licenses/MIT)
|
|
37
|
+
- Apache License, Version 2.0, ([LICENSE-APACHE.txt](https://github.com/bluesky-social/atproto/blob/main/LICENSE-APACHE.txt) or http://www.apache.org/licenses/LICENSE-2.0)
|
|
38
|
+
|
|
39
|
+
Downstream projects and end users may chose either license individually, or both together, at their discretion. The motivation for this dual-licensing is the additional software patent assurance provided by Apache 2.0.
|
package/bin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin-multi-pds.d.ts","sourceRoot":"","sources":["../src/bin-multi-pds.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,CAAA"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import './env.js';
|
|
2
|
+
import getPort from 'get-port';
|
|
3
|
+
import { IntrospectServer } from './introspect.js';
|
|
4
|
+
import { TestPds } from './pds.js';
|
|
5
|
+
import { TestPlc } from './plc.js';
|
|
6
|
+
import { LexiconAuthorityProfile } from './service-profile-lexicon.js';
|
|
7
|
+
import { mockMailer, mockNetworkUtilities } from './util.js';
|
|
8
|
+
const INTROSPECT_PORT = 2581;
|
|
9
|
+
const PRIMARY_PDS_PORT = 2583;
|
|
10
|
+
const PLC_PORT = 2582;
|
|
11
|
+
// The lex-authority account hosts permission-set / space lexicon docs that
|
|
12
|
+
// dev-env PDSes resolve via `lexiconDidAuthority`. Demo apps can log into this
|
|
13
|
+
// account to publish new lexicons (e.g. `space`-typed documents) at runtime.
|
|
14
|
+
const LEX_AUTHORITY_USER = {
|
|
15
|
+
email: 'lex-authority@test.com',
|
|
16
|
+
handle: 'lex-authority.test',
|
|
17
|
+
password: 'hunter2',
|
|
18
|
+
};
|
|
19
|
+
const parsePdsCount = () => {
|
|
20
|
+
const arg = process.argv[2];
|
|
21
|
+
if (arg === undefined)
|
|
22
|
+
return 3;
|
|
23
|
+
const n = Number.parseInt(arg, 10);
|
|
24
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
25
|
+
throw new Error(`Invalid PDS count "${arg}": must be an integer >= 1`);
|
|
26
|
+
}
|
|
27
|
+
return n;
|
|
28
|
+
};
|
|
29
|
+
const run = async () => {
|
|
30
|
+
const totalPdsCount = parsePdsCount();
|
|
31
|
+
const extraPdsCount = totalPdsCount - 1;
|
|
32
|
+
console.log(`
|
|
33
|
+
██████╗
|
|
34
|
+
██╔═══██╗
|
|
35
|
+
██║██╗██║
|
|
36
|
+
██║██║██║
|
|
37
|
+
╚█║████╔╝
|
|
38
|
+
╚╝╚═══╝ protocol
|
|
39
|
+
|
|
40
|
+
[ created by Bluesky ]`);
|
|
41
|
+
const plc = await TestPlc.create({ port: PLC_PORT });
|
|
42
|
+
// Step 1 — scratch PDS. We need an existing PDS to host the lex-authority
|
|
43
|
+
// account creation, but we don't want the scratch to live past startup. The
|
|
44
|
+
// account migrates to the primary PDS once we know its DID.
|
|
45
|
+
const scratchPds = await TestPds.create({
|
|
46
|
+
didPlcUrl: plc.url,
|
|
47
|
+
inviteRequired: false,
|
|
48
|
+
port: await getPort(),
|
|
49
|
+
});
|
|
50
|
+
// Step 2 — create the lex-authority account on the scratch PDS so we can
|
|
51
|
+
// capture its DID before any "real" PDS spins up with `lexiconDidAuthority`
|
|
52
|
+
// pointing at it.
|
|
53
|
+
const lexAuthority = await LexiconAuthorityProfile.create(scratchPds, LEX_AUTHORITY_USER);
|
|
54
|
+
const lexAuthorityDid = lexAuthority.did;
|
|
55
|
+
// Step 3 — primary PDS, configured to resolve lexicons from the authority.
|
|
56
|
+
const primary = await TestPds.create({
|
|
57
|
+
port: PRIMARY_PDS_PORT,
|
|
58
|
+
hostname: 'localhost',
|
|
59
|
+
enableDidDocWithSession: true,
|
|
60
|
+
didPlcUrl: plc.url,
|
|
61
|
+
lexiconDidAuthority: lexAuthorityDid,
|
|
62
|
+
});
|
|
63
|
+
// Step 4 — migrate the authority account to the primary PDS, then publish
|
|
64
|
+
// the seed lexicon docs (permission sets, etc.) at the new home.
|
|
65
|
+
await lexAuthority.migrateTo(primary);
|
|
66
|
+
await lexAuthority.createRecords();
|
|
67
|
+
// Step 5 — extra PDSes, each pointing at the same lex authority.
|
|
68
|
+
const extraPdses = [];
|
|
69
|
+
for (let i = 0; i < extraPdsCount; i++) {
|
|
70
|
+
const domain = `.test${i + 2}`;
|
|
71
|
+
const extra = await TestPds.create({
|
|
72
|
+
didPlcUrl: plc.url,
|
|
73
|
+
port: await getPort(),
|
|
74
|
+
serviceHandleDomains: [domain],
|
|
75
|
+
lexiconDidAuthority: lexAuthorityDid,
|
|
76
|
+
});
|
|
77
|
+
extraPdses.push(extra);
|
|
78
|
+
}
|
|
79
|
+
// Step 6 — close the scratch PDS now that the authority lives on primary.
|
|
80
|
+
await scratchPds.close();
|
|
81
|
+
// Mock network utilities (handle/DID resolution) across the surviving PDSes.
|
|
82
|
+
const allPdsesArray = [primary, ...extraPdses];
|
|
83
|
+
mockNetworkUtilities(allPdsesArray);
|
|
84
|
+
for (const pds of allPdsesArray) {
|
|
85
|
+
mockMailer(pds);
|
|
86
|
+
}
|
|
87
|
+
const introspect = await IntrospectServer.start(INTROSPECT_PORT, plc, allPdsesArray, undefined, undefined, undefined, {
|
|
88
|
+
did: lexAuthorityDid,
|
|
89
|
+
handle: LEX_AUTHORITY_USER.handle,
|
|
90
|
+
password: LEX_AUTHORITY_USER.password,
|
|
91
|
+
pds: primary.url,
|
|
92
|
+
});
|
|
93
|
+
console.log(`🔍 Introspection server http://localhost:${introspect.port}`);
|
|
94
|
+
console.log(`👤 DID Placeholder server ${plc.url}`);
|
|
95
|
+
const allPdses = [
|
|
96
|
+
{ label: 'pds1 (primary)', pds: primary, domain: 'test' },
|
|
97
|
+
...extraPdses.map((pds, i) => ({
|
|
98
|
+
label: `pds${i + 2}`,
|
|
99
|
+
pds,
|
|
100
|
+
domain: `test${i + 2}`,
|
|
101
|
+
})),
|
|
102
|
+
];
|
|
103
|
+
for (const { label, pds } of allPdses) {
|
|
104
|
+
console.log(`🌞 ${label} http://localhost:${pds.port}`);
|
|
105
|
+
}
|
|
106
|
+
console.log(`\n📚 Lex authority ${LEX_AUTHORITY_USER.handle} (${lexAuthorityDid})`);
|
|
107
|
+
console.log(` hosted on pds1 — log in with password "${LEX_AUTHORITY_USER.password}"`);
|
|
108
|
+
// Seed alice/bob/carol on each PDS so each has data that's reachable cross-PDS.
|
|
109
|
+
const seedNames = ['alice', 'bob', 'carol'];
|
|
110
|
+
const seeded = [];
|
|
111
|
+
for (const { label, pds, domain } of allPdses) {
|
|
112
|
+
const agent = pds.getAgent();
|
|
113
|
+
for (const name of seedNames) {
|
|
114
|
+
const handle = `${name}.${domain}`;
|
|
115
|
+
const res = await agent.com.atproto.server.createAccount({
|
|
116
|
+
handle,
|
|
117
|
+
email: `${name}-${domain}@test.com`,
|
|
118
|
+
password: `${name}-pass`,
|
|
119
|
+
});
|
|
120
|
+
seeded.push({ handle, did: res.data.did, pds: label });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
console.log('\n👥 Seeded accounts:');
|
|
124
|
+
for (const acct of seeded) {
|
|
125
|
+
console.log(` ${acct.pds.padEnd(16)} handle=${acct.handle.padEnd(20)} did=${acct.did}`);
|
|
126
|
+
}
|
|
127
|
+
console.log(' (passwords: alice-pass / bob-pass / carol-pass)');
|
|
128
|
+
};
|
|
129
|
+
run();
|
|
130
|
+
//# sourceMappingURL=bin-multi-pds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin-multi-pds.js","sourceRoot":"","sources":["../src/bin-multi-pds.ts"],"names":[],"mappings":"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","sourcesContent":["import './env.js'\nimport getPort from 'get-port'\nimport { IntrospectServer } from './introspect.js'\nimport { TestPds } from './pds.js'\nimport { TestPlc } from './plc.js'\nimport { LexiconAuthorityProfile } from './service-profile-lexicon.js'\nimport { mockMailer, mockNetworkUtilities } from './util.js'\n\nconst INTROSPECT_PORT = 2581\nconst PRIMARY_PDS_PORT = 2583\nconst PLC_PORT = 2582\n\n// The lex-authority account hosts permission-set / space lexicon docs that\n// dev-env PDSes resolve via `lexiconDidAuthority`. Demo apps can log into this\n// account to publish new lexicons (e.g. `space`-typed documents) at runtime.\nconst LEX_AUTHORITY_USER = {\n email: 'lex-authority@test.com',\n handle: 'lex-authority.test',\n password: 'hunter2',\n}\n\nconst parsePdsCount = (): number => {\n const arg = process.argv[2]\n if (arg === undefined) return 3\n const n = Number.parseInt(arg, 10)\n if (!Number.isFinite(n) || n < 1) {\n throw new Error(`Invalid PDS count \"${arg}\": must be an integer >= 1`)\n }\n return n\n}\n\nconst run = async () => {\n const totalPdsCount = parsePdsCount()\n const extraPdsCount = totalPdsCount - 1\n\n console.log(`\n██████╗\n██╔═══██╗\n██║██╗██║\n██║██║██║\n╚█║████╔╝\n ╚╝╚═══╝ protocol\n\n[ created by Bluesky ]`)\n\n const plc = await TestPlc.create({ port: PLC_PORT })\n\n // Step 1 — scratch PDS. We need an existing PDS to host the lex-authority\n // account creation, but we don't want the scratch to live past startup. The\n // account migrates to the primary PDS once we know its DID.\n const scratchPds = await TestPds.create({\n didPlcUrl: plc.url,\n inviteRequired: false,\n port: await getPort(),\n })\n\n // Step 2 — create the lex-authority account on the scratch PDS so we can\n // capture its DID before any \"real\" PDS spins up with `lexiconDidAuthority`\n // pointing at it.\n const lexAuthority = await LexiconAuthorityProfile.create(\n scratchPds,\n LEX_AUTHORITY_USER,\n )\n const lexAuthorityDid = lexAuthority.did\n\n // Step 3 — primary PDS, configured to resolve lexicons from the authority.\n const primary = await TestPds.create({\n port: PRIMARY_PDS_PORT,\n hostname: 'localhost',\n enableDidDocWithSession: true,\n didPlcUrl: plc.url,\n lexiconDidAuthority: lexAuthorityDid,\n })\n\n // Step 4 — migrate the authority account to the primary PDS, then publish\n // the seed lexicon docs (permission sets, etc.) at the new home.\n await lexAuthority.migrateTo(primary)\n await lexAuthority.createRecords()\n\n // Step 5 — extra PDSes, each pointing at the same lex authority.\n const extraPdses: TestPds[] = []\n for (let i = 0; i < extraPdsCount; i++) {\n const domain = `.test${i + 2}`\n const extra = await TestPds.create({\n didPlcUrl: plc.url,\n port: await getPort(),\n serviceHandleDomains: [domain],\n lexiconDidAuthority: lexAuthorityDid,\n })\n extraPdses.push(extra)\n }\n\n // Step 6 — close the scratch PDS now that the authority lives on primary.\n await scratchPds.close()\n\n // Mock network utilities (handle/DID resolution) across the surviving PDSes.\n const allPdsesArray = [primary, ...extraPdses]\n mockNetworkUtilities(allPdsesArray)\n for (const pds of allPdsesArray) {\n mockMailer(pds)\n }\n\n const introspect = await IntrospectServer.start(\n INTROSPECT_PORT,\n plc,\n allPdsesArray,\n undefined,\n undefined,\n undefined,\n {\n did: lexAuthorityDid,\n handle: LEX_AUTHORITY_USER.handle,\n password: LEX_AUTHORITY_USER.password,\n pds: primary.url,\n },\n )\n\n console.log(`🔍 Introspection server http://localhost:${introspect.port}`)\n console.log(`👤 DID Placeholder server ${plc.url}`)\n\n const allPdses: { label: string; pds: TestPds; domain: string }[] = [\n { label: 'pds1 (primary)', pds: primary, domain: 'test' },\n ...extraPdses.map((pds, i) => ({\n label: `pds${i + 2}`,\n pds,\n domain: `test${i + 2}`,\n })),\n ]\n\n for (const { label, pds } of allPdses) {\n console.log(`🌞 ${label} http://localhost:${pds.port}`)\n }\n\n console.log(\n `\\n📚 Lex authority ${LEX_AUTHORITY_USER.handle} (${lexAuthorityDid})`,\n )\n console.log(\n ` hosted on pds1 — log in with password \"${LEX_AUTHORITY_USER.password}\"`,\n )\n\n // Seed alice/bob/carol on each PDS so each has data that's reachable cross-PDS.\n const seedNames = ['alice', 'bob', 'carol']\n const seeded: { handle: string; did: string; pds: string }[] = []\n for (const { label, pds, domain } of allPdses) {\n const agent = pds.getAgent()\n for (const name of seedNames) {\n const handle = `${name}.${domain}`\n const res = await agent.com.atproto.server.createAccount({\n handle,\n email: `${name}-${domain}@test.com`,\n password: `${name}-pass`,\n })\n seeded.push({ handle, did: res.data.did, pds: label })\n }\n }\n\n console.log('\\n👥 Seeded accounts:')\n for (const acct of seeded) {\n console.log(\n ` ${acct.pds.padEnd(16)} handle=${acct.handle.padEnd(20)} did=${acct.did}`,\n )\n }\n console.log(' (passwords: alice-pass / bob-pass / carol-pass)')\n}\n\nrun()\n"]}
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,CAAA"}
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import './env.js';
|
|
2
|
+
import { generateMockSetup } from './mock/index.js';
|
|
3
|
+
import { TestNetwork } from './network.js';
|
|
4
|
+
import { mockMailer } from './util.js';
|
|
5
|
+
const run = async () => {
|
|
6
|
+
console.log(`
|
|
7
|
+
██████╗
|
|
8
|
+
██╔═══██╗
|
|
9
|
+
██║██╗██║
|
|
10
|
+
██║██║██║
|
|
11
|
+
╚█║████╔╝
|
|
12
|
+
╚╝╚═══╝ protocol
|
|
13
|
+
|
|
14
|
+
[ created by Bluesky ]`);
|
|
15
|
+
const network = await TestNetwork.create({
|
|
16
|
+
pds: {
|
|
17
|
+
port: 2583,
|
|
18
|
+
hostname: 'localhost',
|
|
19
|
+
enableDidDocWithSession: true,
|
|
20
|
+
},
|
|
21
|
+
bsky: {
|
|
22
|
+
dbPostgresSchema: 'bsky',
|
|
23
|
+
port: 2584,
|
|
24
|
+
publicUrl: 'http://localhost:2584',
|
|
25
|
+
},
|
|
26
|
+
plc: { port: 2582 },
|
|
27
|
+
ozone: {
|
|
28
|
+
port: 2587,
|
|
29
|
+
chatUrl: 'http://localhost:2590', // must run separate chat service
|
|
30
|
+
chatDid: 'did:example:chat',
|
|
31
|
+
dbMaterializedViewRefreshIntervalMs: 30_000,
|
|
32
|
+
},
|
|
33
|
+
introspect: { port: 2581 },
|
|
34
|
+
});
|
|
35
|
+
mockMailer(network.pds);
|
|
36
|
+
if (network.introspect) {
|
|
37
|
+
console.log(`🔍 Dev-env introspection server http://localhost:${network.introspect.port}`);
|
|
38
|
+
}
|
|
39
|
+
console.log(`👤 DID Placeholder server http://localhost:${network.plc.port}`);
|
|
40
|
+
console.log(`🌞 Main PDS http://localhost:${network.pds.port}`);
|
|
41
|
+
console.log(`🌞 Main PDS account DB`, network.pds.ctx.cfg.db.accountDbLoc);
|
|
42
|
+
console.log(`🔨 Lexicon authority DID ${network.pds.ctx.cfg.lexicon.didAuthority}`);
|
|
43
|
+
console.log(`🗼 Ozone server http://localhost:${network.ozone.port}`);
|
|
44
|
+
console.log(`🗼 Ozone service DID ${network.ozone.ctx.cfg.service.did}`);
|
|
45
|
+
console.log(`🔄 Bsync server http://localhost:${network.bsync.port}`);
|
|
46
|
+
console.log(`🌅 Bsky Appview http://localhost:${network.bsky.port}`);
|
|
47
|
+
console.log(`🌅 Bsky Appview DID ${network.bsky.serverDid}`);
|
|
48
|
+
for (const fg of network.feedGens) {
|
|
49
|
+
console.log(`🤖 Feed Generator (${fg.did}) http://localhost:${fg.port}`);
|
|
50
|
+
}
|
|
51
|
+
console.time('✅ Dev environment is ready');
|
|
52
|
+
await generateMockSetup(network);
|
|
53
|
+
console.timeEnd('✅ Dev environment is ready');
|
|
54
|
+
};
|
|
55
|
+
run();
|
|
56
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,CAAA;AACjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE;IACrB,OAAO,CAAC,GAAG,CAAC;;;;;;;;uBAQS,CAAC,CAAA;IAEtB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC;QACvC,GAAG,EAAE;YACH,IAAI,EAAE,IAAI;YACV,QAAQ,EAAE,WAAW;YACrB,uBAAuB,EAAE,IAAI;SAC9B;QACD,IAAI,EAAE;YACJ,gBAAgB,EAAE,MAAM;YACxB,IAAI,EAAE,IAAI;YACV,SAAS,EAAE,uBAAuB;SACnC;QACD,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;QACnB,KAAK,EAAE;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,uBAAuB,EAAE,iCAAiC;YACnE,OAAO,EAAE,kBAAkB;YAC3B,mCAAmC,EAAE,MAAM;SAC5C;QACD,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;KAC3B,CAAC,CAAA;IACF,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAEvB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CACT,oDAAoD,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,CAC9E,CAAA;IACH,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,8CAA8C,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;IAC7E,OAAO,CAAC,GAAG,CAAC,gCAAgC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;IAC/D,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,CAAA;IAC1E,OAAO,CAAC,GAAG,CACT,4BAA4B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,CACvE,CAAA;IACD,OAAO,CAAC,GAAG,CAAC,oCAAoC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IACrE,OAAO,CAAC,GAAG,CAAC,wBAAwB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;IACxE,OAAO,CAAC,GAAG,CAAC,oCAAoC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IACrE,OAAO,CAAC,GAAG,CAAC,oCAAoC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACpE,OAAO,CAAC,GAAG,CAAC,uBAAuB,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5D,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC,GAAG,sBAAsB,EAAE,CAAC,IAAI,EAAE,CAAC,CAAA;IAC1E,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAA;IAC1C,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAChC,OAAO,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAA;AAC/C,CAAC,CAAA;AAED,GAAG,EAAE,CAAA","sourcesContent":["import './env.js'\nimport { generateMockSetup } from './mock/index.js'\nimport { TestNetwork } from './network.js'\nimport { mockMailer } from './util.js'\n\nconst run = async () => {\n console.log(`\n██████╗\n██╔═══██╗\n██║██╗██║\n██║██║██║\n╚█║████╔╝\n ╚╝╚═══╝ protocol\n\n[ created by Bluesky ]`)\n\n const network = await TestNetwork.create({\n pds: {\n port: 2583,\n hostname: 'localhost',\n enableDidDocWithSession: true,\n },\n bsky: {\n dbPostgresSchema: 'bsky',\n port: 2584,\n publicUrl: 'http://localhost:2584',\n },\n plc: { port: 2582 },\n ozone: {\n port: 2587,\n chatUrl: 'http://localhost:2590', // must run separate chat service\n chatDid: 'did:example:chat',\n dbMaterializedViewRefreshIntervalMs: 30_000,\n },\n introspect: { port: 2581 },\n })\n mockMailer(network.pds)\n\n if (network.introspect) {\n console.log(\n `🔍 Dev-env introspection server http://localhost:${network.introspect.port}`,\n )\n }\n console.log(`👤 DID Placeholder server http://localhost:${network.plc.port}`)\n console.log(`🌞 Main PDS http://localhost:${network.pds.port}`)\n console.log(`🌞 Main PDS account DB`, network.pds.ctx.cfg.db.accountDbLoc)\n console.log(\n `🔨 Lexicon authority DID ${network.pds.ctx.cfg.lexicon.didAuthority}`,\n )\n console.log(`🗼 Ozone server http://localhost:${network.ozone.port}`)\n console.log(`🗼 Ozone service DID ${network.ozone.ctx.cfg.service.did}`)\n console.log(`🔄 Bsync server http://localhost:${network.bsync.port}`)\n console.log(`🌅 Bsky Appview http://localhost:${network.bsky.port}`)\n console.log(`🌅 Bsky Appview DID ${network.bsky.serverDid}`)\n for (const fg of network.feedGens) {\n console.log(`🤖 Feed Generator (${fg.did}) http://localhost:${fg.port}`)\n }\n\n console.time('✅ Dev environment is ready')\n await generateMockSetup(network)\n console.timeEnd('✅ Dev environment is ready')\n}\n\nrun()\n"]}
|
package/dist/bsky.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AtpAgent } from '@atproto/api';
|
|
2
|
+
import * as bsky from '@atproto/bsky';
|
|
3
|
+
import { Client } from '@atproto/lex';
|
|
4
|
+
import type { BskyConfig } from './types.js';
|
|
5
|
+
export * from '@atproto/bsky';
|
|
6
|
+
export declare class TestBsky {
|
|
7
|
+
url: string;
|
|
8
|
+
port: number;
|
|
9
|
+
db: bsky.Database;
|
|
10
|
+
server: bsky.BskyAppView;
|
|
11
|
+
dataplane: bsky.DataPlaneServer;
|
|
12
|
+
bsyncSub: bsky.BsyncSubscription;
|
|
13
|
+
sub: bsky.RepoSubscription;
|
|
14
|
+
serverDid: string;
|
|
15
|
+
constructor(url: string, port: number, db: bsky.Database, server: bsky.BskyAppView, dataplane: bsky.DataPlaneServer, bsyncSub: bsky.BsyncSubscription, sub: bsky.RepoSubscription, serverDid: string);
|
|
16
|
+
static create(cfg: BskyConfig): Promise<TestBsky>;
|
|
17
|
+
get ctx(): bsky.AppContext;
|
|
18
|
+
getAgent(): AtpAgent;
|
|
19
|
+
getClient(): Client;
|
|
20
|
+
adminAuth(): string;
|
|
21
|
+
adminAuthHeaders(): {
|
|
22
|
+
authorization: string;
|
|
23
|
+
};
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=bsky.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bsky.d.ts","sourceRoot":"","sources":["../src/bsky.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAGrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC5C,cAAc,eAAe,CAAA;AAE7B,qBAAa,QAAQ;IAEV,GAAG,EAAE,MAAM;IACX,IAAI,EAAE,MAAM;IACZ,EAAE,EAAE,IAAI,CAAC,QAAQ;IACjB,MAAM,EAAE,IAAI,CAAC,WAAW;IACxB,SAAS,EAAE,IAAI,CAAC,eAAe;IAC/B,QAAQ,EAAE,IAAI,CAAC,iBAAiB;IAChC,GAAG,EAAE,IAAI,CAAC,gBAAgB;IAC1B,SAAS,EAAE,MAAM;IAR1B,YACS,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,IAAI,CAAC,QAAQ,EACjB,MAAM,EAAE,IAAI,CAAC,WAAW,EACxB,SAAS,EAAE,IAAI,CAAC,eAAe,EAC/B,QAAQ,EAAE,IAAI,CAAC,iBAAiB,EAChC,GAAG,EAAE,IAAI,CAAC,gBAAgB,EAC1B,SAAS,EAAE,MAAM,EACtB;IAEJ,OAAa,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqHtD;IAED,IAAI,GAAG,IAAI,IAAI,CAAC,UAAU,CAEzB;IAED,QAAQ,IAAI,QAAQ,CAInB;IAED,SAAS,IAAI,MAAM,CAIlB;IAED,SAAS,IAAI,MAAM,CAMlB;IAED,gBAAgB;QAEZ,aAAa;MAEhB;IAEK,KAAK,kBAmBV;IAEK,CAAC,MAAM,CAAC,YAAY,CAAC,kBAE1B;CACF"}
|
package/dist/bsky.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { Client as PlcClient } from '@did-plc/lib';
|
|
2
|
+
import getPort from 'get-port';
|
|
3
|
+
import * as ui8 from 'uint8arrays';
|
|
4
|
+
import { AtpAgent } from '@atproto/api';
|
|
5
|
+
import * as bsky from '@atproto/bsky';
|
|
6
|
+
import { Secp256k1Keypair } from '@atproto/crypto';
|
|
7
|
+
import { Client } from '@atproto/lex';
|
|
8
|
+
import { ADMIN_PASSWORD, EXAMPLE_LABELER } from './const.js';
|
|
9
|
+
export * from '@atproto/bsky';
|
|
10
|
+
export class TestBsky {
|
|
11
|
+
constructor(url, port, db, server, dataplane, bsyncSub, sub, serverDid) {
|
|
12
|
+
this.url = url;
|
|
13
|
+
this.port = port;
|
|
14
|
+
this.db = db;
|
|
15
|
+
this.server = server;
|
|
16
|
+
this.dataplane = dataplane;
|
|
17
|
+
this.bsyncSub = bsyncSub;
|
|
18
|
+
this.sub = sub;
|
|
19
|
+
this.serverDid = serverDid;
|
|
20
|
+
}
|
|
21
|
+
static async create(cfg) {
|
|
22
|
+
const serviceKeypair = cfg.privateKey
|
|
23
|
+
? await Secp256k1Keypair.import(cfg.privateKey)
|
|
24
|
+
: await Secp256k1Keypair.create();
|
|
25
|
+
const plcClient = new PlcClient(cfg.plcUrl);
|
|
26
|
+
const port = cfg.port || (await getPort());
|
|
27
|
+
const url = `http://localhost:${port}`;
|
|
28
|
+
const serverDid = (await plcClient.createDid({
|
|
29
|
+
signingKey: serviceKeypair.did(),
|
|
30
|
+
rotationKeys: [serviceKeypair.did()],
|
|
31
|
+
handle: 'bsky.test',
|
|
32
|
+
pds: `http://localhost:${port}`,
|
|
33
|
+
signer: serviceKeypair,
|
|
34
|
+
}));
|
|
35
|
+
const endpoint = `http://localhost:${port}`;
|
|
36
|
+
await plcClient.updateData(serverDid, serviceKeypair, (x) => {
|
|
37
|
+
x.services['bsky_notif'] = {
|
|
38
|
+
type: 'BskyNotificationService',
|
|
39
|
+
endpoint,
|
|
40
|
+
};
|
|
41
|
+
x.services['bsky_appview'] = {
|
|
42
|
+
type: 'BskyAppView',
|
|
43
|
+
endpoint,
|
|
44
|
+
};
|
|
45
|
+
return x;
|
|
46
|
+
});
|
|
47
|
+
// shared across server, ingester, and indexer in order to share pool, avoid too many pg connections.
|
|
48
|
+
const db = new bsky.Database({
|
|
49
|
+
url: cfg.dbPostgresUrl,
|
|
50
|
+
schema: cfg.dbPostgresSchema,
|
|
51
|
+
poolSize: 10,
|
|
52
|
+
});
|
|
53
|
+
const dataplanePort = await getPort();
|
|
54
|
+
const dataplane = await bsky.DataPlaneServer.create(db, dataplanePort, cfg.plcUrl);
|
|
55
|
+
const config = new bsky.ServerConfig({
|
|
56
|
+
version: 'unknown',
|
|
57
|
+
port,
|
|
58
|
+
didPlcUrl: cfg.plcUrl,
|
|
59
|
+
publicUrl: 'https://bsky.public.url',
|
|
60
|
+
serverDid,
|
|
61
|
+
alternateAudienceDids: [],
|
|
62
|
+
dataplaneUrls: [`http://localhost:${dataplanePort}`],
|
|
63
|
+
dataplaneHttpVersion: '1.1',
|
|
64
|
+
bsyncHttpVersion: '1.1',
|
|
65
|
+
bsyncApiKey: 'bsync-api-key',
|
|
66
|
+
modServiceDid: cfg.modServiceDid ?? 'did:example:invalidMod',
|
|
67
|
+
labelsFromIssuerDids: [EXAMPLE_LABELER],
|
|
68
|
+
bigThreadUris: new Set(),
|
|
69
|
+
maxThreadParents: cfg.maxThreadParents ?? 50,
|
|
70
|
+
disableSsrfProtection: true,
|
|
71
|
+
searchTagsHide: new Set(),
|
|
72
|
+
searchTagsHideAll: new Set(),
|
|
73
|
+
threadTagsBumpDown: new Set(),
|
|
74
|
+
threadTagsHide: new Set(),
|
|
75
|
+
visibilityTagHide: '',
|
|
76
|
+
visibilityTagRankPrefix: '',
|
|
77
|
+
debugFieldAllowedDids: new Set(),
|
|
78
|
+
draftsLimit: 500,
|
|
79
|
+
...cfg,
|
|
80
|
+
adminPasswords: [ADMIN_PASSWORD],
|
|
81
|
+
etcdHosts: [],
|
|
82
|
+
});
|
|
83
|
+
// Separate migration db in case migration changes some connection state that we need in the tests, e.g. "alter database ... set ..."
|
|
84
|
+
const migrationDb = new bsky.Database({
|
|
85
|
+
url: cfg.dbPostgresUrl,
|
|
86
|
+
schema: cfg.dbPostgresSchema,
|
|
87
|
+
});
|
|
88
|
+
if (cfg.migration) {
|
|
89
|
+
await migrationDb.migrateToOrThrow(cfg.migration);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
await migrationDb.migrateToLatestOrThrow();
|
|
93
|
+
}
|
|
94
|
+
await migrationDb.close();
|
|
95
|
+
// api server
|
|
96
|
+
const server = bsky.BskyAppView.create({
|
|
97
|
+
config,
|
|
98
|
+
signingKey: serviceKeypair,
|
|
99
|
+
});
|
|
100
|
+
const bsyncSub = new bsky.BsyncSubscription({
|
|
101
|
+
config,
|
|
102
|
+
db,
|
|
103
|
+
});
|
|
104
|
+
const sub = new bsky.RepoSubscription({
|
|
105
|
+
service: cfg.repoProvider,
|
|
106
|
+
db,
|
|
107
|
+
idResolver: dataplane.idResolver,
|
|
108
|
+
});
|
|
109
|
+
await server.start();
|
|
110
|
+
bsyncSub.start();
|
|
111
|
+
void sub.start();
|
|
112
|
+
return new TestBsky(url, port, db, server, dataplane, bsyncSub, sub, serverDid);
|
|
113
|
+
}
|
|
114
|
+
get ctx() {
|
|
115
|
+
return this.server.ctx;
|
|
116
|
+
}
|
|
117
|
+
getAgent() {
|
|
118
|
+
const agent = new AtpAgent({ service: this.url });
|
|
119
|
+
agent.configureLabelers([EXAMPLE_LABELER]);
|
|
120
|
+
return agent;
|
|
121
|
+
}
|
|
122
|
+
getClient() {
|
|
123
|
+
const client = new Client({ service: this.url });
|
|
124
|
+
client.setLabelers([EXAMPLE_LABELER]);
|
|
125
|
+
return client;
|
|
126
|
+
}
|
|
127
|
+
adminAuth() {
|
|
128
|
+
const [password] = this.ctx.cfg.adminPasswords;
|
|
129
|
+
return ('Basic ' +
|
|
130
|
+
ui8.toString(ui8.fromString(`admin:${password}`, 'utf8'), 'base64pad'));
|
|
131
|
+
}
|
|
132
|
+
adminAuthHeaders() {
|
|
133
|
+
return {
|
|
134
|
+
authorization: this.adminAuth(),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
async close() {
|
|
138
|
+
// @TODO Use disposable stack when it becomes available (Node24+)
|
|
139
|
+
try {
|
|
140
|
+
await this.server.destroy();
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
try {
|
|
144
|
+
await this.bsyncSub.destroy();
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
try {
|
|
148
|
+
await this.dataplane.destroy();
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
try {
|
|
152
|
+
await this.sub.destroy();
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
await this.db.close();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async [Symbol.asyncDispose]() {
|
|
162
|
+
await this.close();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=bsky.js.map
|
package/dist/bsky.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bsky.js","sourceRoot":"","sources":["../src/bsky.ts"],"names":[],"mappings":"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","sourcesContent":["import { Client as PlcClient } from '@did-plc/lib'\nimport getPort from 'get-port'\nimport * as ui8 from 'uint8arrays'\nimport { AtpAgent } from '@atproto/api'\nimport * as bsky from '@atproto/bsky'\nimport { Secp256k1Keypair } from '@atproto/crypto'\nimport { Client } from '@atproto/lex'\nimport type { DidString } from '@atproto/syntax'\nimport { ADMIN_PASSWORD, EXAMPLE_LABELER } from './const.js'\nimport type { BskyConfig } from './types.js'\nexport * from '@atproto/bsky'\n\nexport class TestBsky {\n constructor(\n public url: string,\n public port: number,\n public db: bsky.Database,\n public server: bsky.BskyAppView,\n public dataplane: bsky.DataPlaneServer,\n public bsyncSub: bsky.BsyncSubscription,\n public sub: bsky.RepoSubscription,\n public serverDid: string,\n ) {}\n\n static async create(cfg: BskyConfig): Promise<TestBsky> {\n const serviceKeypair = cfg.privateKey\n ? await Secp256k1Keypair.import(cfg.privateKey)\n : await Secp256k1Keypair.create()\n const plcClient = new PlcClient(cfg.plcUrl)\n\n const port = cfg.port || (await getPort())\n const url = `http://localhost:${port}`\n const serverDid = (await plcClient.createDid({\n signingKey: serviceKeypair.did(),\n rotationKeys: [serviceKeypair.did()],\n handle: 'bsky.test',\n pds: `http://localhost:${port}`,\n signer: serviceKeypair,\n })) as DidString\n\n const endpoint = `http://localhost:${port}`\n\n await plcClient.updateData(serverDid, serviceKeypair, (x) => {\n x.services['bsky_notif'] = {\n type: 'BskyNotificationService',\n endpoint,\n }\n x.services['bsky_appview'] = {\n type: 'BskyAppView',\n endpoint,\n }\n return x\n })\n\n // shared across server, ingester, and indexer in order to share pool, avoid too many pg connections.\n const db = new bsky.Database({\n url: cfg.dbPostgresUrl,\n schema: cfg.dbPostgresSchema,\n poolSize: 10,\n })\n\n const dataplanePort = await getPort()\n const dataplane = await bsky.DataPlaneServer.create(\n db,\n dataplanePort,\n cfg.plcUrl,\n )\n\n const config = new bsky.ServerConfig({\n version: 'unknown',\n port,\n didPlcUrl: cfg.plcUrl,\n publicUrl: 'https://bsky.public.url',\n serverDid,\n alternateAudienceDids: [],\n dataplaneUrls: [`http://localhost:${dataplanePort}`],\n dataplaneHttpVersion: '1.1',\n bsyncHttpVersion: '1.1',\n bsyncApiKey: 'bsync-api-key',\n modServiceDid: cfg.modServiceDid ?? 'did:example:invalidMod',\n labelsFromIssuerDids: [EXAMPLE_LABELER],\n bigThreadUris: new Set(),\n maxThreadParents: cfg.maxThreadParents ?? 50,\n disableSsrfProtection: true,\n searchTagsHide: new Set(),\n searchTagsHideAll: new Set(),\n threadTagsBumpDown: new Set(),\n threadTagsHide: new Set(),\n visibilityTagHide: '',\n visibilityTagRankPrefix: '',\n debugFieldAllowedDids: new Set(),\n draftsLimit: 500,\n ...cfg,\n adminPasswords: [ADMIN_PASSWORD],\n etcdHosts: [],\n })\n\n // Separate migration db in case migration changes some connection state that we need in the tests, e.g. \"alter database ... set ...\"\n const migrationDb = new bsky.Database({\n url: cfg.dbPostgresUrl,\n schema: cfg.dbPostgresSchema,\n })\n if (cfg.migration) {\n await migrationDb.migrateToOrThrow(cfg.migration)\n } else {\n await migrationDb.migrateToLatestOrThrow()\n }\n await migrationDb.close()\n\n // api server\n const server = bsky.BskyAppView.create({\n config,\n signingKey: serviceKeypair,\n })\n\n const bsyncSub = new bsky.BsyncSubscription({\n config,\n db,\n })\n\n const sub = new bsky.RepoSubscription({\n service: cfg.repoProvider,\n db,\n idResolver: dataplane.idResolver,\n })\n\n await server.start()\n\n bsyncSub.start()\n void sub.start()\n\n return new TestBsky(\n url,\n port,\n db,\n server,\n dataplane,\n bsyncSub,\n sub,\n serverDid,\n )\n }\n\n get ctx(): bsky.AppContext {\n return this.server.ctx\n }\n\n getAgent(): AtpAgent {\n const agent = new AtpAgent({ service: this.url })\n agent.configureLabelers([EXAMPLE_LABELER])\n return agent\n }\n\n getClient(): Client {\n const client = new Client({ service: this.url })\n client.setLabelers([EXAMPLE_LABELER])\n return client\n }\n\n adminAuth(): string {\n const [password] = this.ctx.cfg.adminPasswords\n return (\n 'Basic ' +\n ui8.toString(ui8.fromString(`admin:${password}`, 'utf8'), 'base64pad')\n )\n }\n\n adminAuthHeaders() {\n return {\n authorization: this.adminAuth(),\n }\n }\n\n async close() {\n // @TODO Use disposable stack when it becomes available (Node24+)\n try {\n await this.server.destroy()\n } finally {\n try {\n await this.bsyncSub.destroy()\n } finally {\n try {\n await this.dataplane.destroy()\n } finally {\n try {\n await this.sub.destroy()\n } finally {\n await this.db.close()\n }\n }\n }\n }\n }\n\n async [Symbol.asyncDispose]() {\n await this.close()\n }\n}\n"]}
|
package/dist/bsync.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as bsync from '@atproto/bsync';
|
|
2
|
+
import type { BsyncConfig } from './types.js';
|
|
3
|
+
export declare class TestBsync {
|
|
4
|
+
url: string;
|
|
5
|
+
port: number;
|
|
6
|
+
service: bsync.BsyncService;
|
|
7
|
+
constructor(url: string, port: number, service: bsync.BsyncService);
|
|
8
|
+
static create(cfg: BsyncConfig): Promise<TestBsync>;
|
|
9
|
+
get ctx(): bsync.AppContext;
|
|
10
|
+
/**
|
|
11
|
+
* Current head (max id) of each operation stream. Used to wait for the bsky
|
|
12
|
+
* bsync subscription to catch up in tests, without waiting for the long-poll
|
|
13
|
+
* timeout.
|
|
14
|
+
*/
|
|
15
|
+
getStreamHeads(): Promise<{
|
|
16
|
+
op?: string;
|
|
17
|
+
mute?: string;
|
|
18
|
+
notif?: string;
|
|
19
|
+
}>;
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=bsync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bsync.d.ts","sourceRoot":"","sources":["../src/bsync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,qBAAa,SAAS;IAEX,GAAG,EAAE,MAAM;IACX,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,KAAK,CAAC,YAAY;IAHpC,YACS,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,KAAK,CAAC,YAAY,EAChC;IAEJ,OAAa,MAAM,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAmBxD;IAED,IAAI,GAAG,IAAI,KAAK,CAAC,UAAU,CAE1B;IAED;;;;OAIG;IACG,cAAc,IAAI,OAAO,CAAC;QAC9B,EAAE,CAAC,EAAE,MAAM,CAAA;QACX,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAC,CAeD;IAEK,KAAK,kBAEV;CACF"}
|
package/dist/bsync.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import getPort from 'get-port';
|
|
2
|
+
import * as bsync from '@atproto/bsync';
|
|
3
|
+
export class TestBsync {
|
|
4
|
+
constructor(url, port, service) {
|
|
5
|
+
this.url = url;
|
|
6
|
+
this.port = port;
|
|
7
|
+
this.service = service;
|
|
8
|
+
}
|
|
9
|
+
static async create(cfg) {
|
|
10
|
+
const port = cfg.port || (await getPort());
|
|
11
|
+
const url = `http://localhost:${port}`;
|
|
12
|
+
const config = bsync.envToCfg({
|
|
13
|
+
port,
|
|
14
|
+
apiKeys: cfg.apiKeys ?? ['api-key'],
|
|
15
|
+
dbSchema: 'bsync',
|
|
16
|
+
// Keep the pool small: a bsync runs alongside every test network, so a
|
|
17
|
+
// default-sized pool per network quickly exhausts postgres connections.
|
|
18
|
+
dbPoolSize: cfg.dbPoolSize ?? 5,
|
|
19
|
+
...cfg,
|
|
20
|
+
});
|
|
21
|
+
const service = await bsync.BsyncService.create(config);
|
|
22
|
+
await service.ctx.db.migrateToLatestOrThrow();
|
|
23
|
+
await service.start();
|
|
24
|
+
return new TestBsync(url, port, service);
|
|
25
|
+
}
|
|
26
|
+
get ctx() {
|
|
27
|
+
return this.service.ctx;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Current head (max id) of each operation stream. Used to wait for the bsky
|
|
31
|
+
* bsync subscription to catch up in tests, without waiting for the long-poll
|
|
32
|
+
* timeout.
|
|
33
|
+
*/
|
|
34
|
+
async getStreamHeads() {
|
|
35
|
+
const db = this.ctx.db.db;
|
|
36
|
+
const max = async (table) => {
|
|
37
|
+
const row = await db
|
|
38
|
+
.selectFrom(table)
|
|
39
|
+
.select((eb) => eb.fn.max('id').as('id'))
|
|
40
|
+
.executeTakeFirst();
|
|
41
|
+
return row?.id != null ? String(row.id) : undefined;
|
|
42
|
+
};
|
|
43
|
+
const [op, mute, notif] = await Promise.all([
|
|
44
|
+
max('operation'),
|
|
45
|
+
max('mute_op'),
|
|
46
|
+
max('notif_op'),
|
|
47
|
+
]);
|
|
48
|
+
return { op, mute, notif };
|
|
49
|
+
}
|
|
50
|
+
async close() {
|
|
51
|
+
await this.service.destroy();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=bsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bsync.js","sourceRoot":"","sources":["../src/bsync.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,UAAU,CAAA;AAC9B,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAA;AAGvC,MAAM,OAAO,SAAS;IACpB,YACS,GAAW,EACX,IAAY,EACZ,OAA2B;mBAF3B,GAAG;oBACH,IAAI;uBACJ,OAAO;IACb,CAAC;IAEJ,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAgB;QAClC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,OAAO,EAAE,CAAC,CAAA;QAC1C,MAAM,GAAG,GAAG,oBAAoB,IAAI,EAAE,CAAA;QAEtC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC;YAC5B,IAAI;YACJ,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC;YACnC,QAAQ,EAAE,OAAO;YACjB,uEAAuE;YACvE,wEAAwE;YACxE,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,CAAC;YAC/B,GAAG,GAAG;SACP,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QACvD,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,sBAAsB,EAAE,CAAA;QAC7C,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;QAErB,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IAC1C,CAAC;IAED,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAA;IACzB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,cAAc;QAKlB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAA;QACzB,MAAM,GAAG,GAAG,KAAK,EAAE,KAA2C,EAAE,EAAE;YAChE,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,KAAK,CAAC;iBACjB,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;iBACxC,gBAAgB,EAAE,CAAA;YACrB,OAAO,GAAG,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACrD,CAAC,CAAA;QACD,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC1C,GAAG,CAAC,WAAW,CAAC;YAChB,GAAG,CAAC,SAAS,CAAC;YACd,GAAG,CAAC,UAAU,CAAC;SAChB,CAAC,CAAA;QACF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAA;IAC9B,CAAC;CACF","sourcesContent":["import getPort from 'get-port'\nimport * as bsync from '@atproto/bsync'\nimport type { BsyncConfig } from './types.js'\n\nexport class TestBsync {\n constructor(\n public url: string,\n public port: number,\n public service: bsync.BsyncService,\n ) {}\n\n static async create(cfg: BsyncConfig): Promise<TestBsync> {\n const port = cfg.port || (await getPort())\n const url = `http://localhost:${port}`\n\n const config = bsync.envToCfg({\n port,\n apiKeys: cfg.apiKeys ?? ['api-key'],\n dbSchema: 'bsync',\n // Keep the pool small: a bsync runs alongside every test network, so a\n // default-sized pool per network quickly exhausts postgres connections.\n dbPoolSize: cfg.dbPoolSize ?? 5,\n ...cfg,\n })\n\n const service = await bsync.BsyncService.create(config)\n await service.ctx.db.migrateToLatestOrThrow()\n await service.start()\n\n return new TestBsync(url, port, service)\n }\n\n get ctx(): bsync.AppContext {\n return this.service.ctx\n }\n\n /**\n * Current head (max id) of each operation stream. Used to wait for the bsky\n * bsync subscription to catch up in tests, without waiting for the long-poll\n * timeout.\n */\n async getStreamHeads(): Promise<{\n op?: string\n mute?: string\n notif?: string\n }> {\n const db = this.ctx.db.db\n const max = async (table: 'operation' | 'mute_op' | 'notif_op') => {\n const row = await db\n .selectFrom(table)\n .select((eb) => eb.fn.max('id').as('id'))\n .executeTakeFirst()\n return row?.id != null ? String(row.id) : undefined\n }\n const [op, mute, notif] = await Promise.all([\n max('operation'),\n max('mute_op'),\n max('notif_op'),\n ])\n return { op, mute, notif }\n }\n\n async close() {\n await this.service.destroy()\n }\n}\n"]}
|
package/dist/const.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../src/const.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,eAAe,CAAA;AAC1C,eAAO,MAAM,UAAU,eAAe,CAAA;AACtC,eAAO,MAAM,eAAe,wBAAwB,CAAA"}
|
package/dist/const.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"const.js","sourceRoot":"","sources":["../src/const.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAA;AAC1C,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAA;AACtC,MAAM,CAAC,MAAM,eAAe,GAAG,qBAAqB,CAAA","sourcesContent":["export const ADMIN_PASSWORD = 'admin-pass'\nexport const JWT_SECRET = 'jwt-secret'\nexport const EXAMPLE_LABELER = 'did:example:labeler'\n"]}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":""}
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// NOTE: this file should be imported first, particularly before `@atproto/common` (for logging), to ensure that environment variables are respected in library code
|
|
2
|
+
import { config } from 'dotenv';
|
|
3
|
+
const env = process.env.ENV;
|
|
4
|
+
if (env) {
|
|
5
|
+
config({ path: `./.${env}.env` });
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
config();
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=env.js.map
|