@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.
Files changed (187) hide show
  1. package/CHANGELOG.md +3424 -0
  2. package/LICENSE.txt +7 -0
  3. package/README.md +39 -0
  4. package/bin.js +7 -0
  5. package/dist/bin-multi-pds.d.ts +2 -0
  6. package/dist/bin-multi-pds.d.ts.map +1 -0
  7. package/dist/bin-multi-pds.js +130 -0
  8. package/dist/bin-multi-pds.js.map +1 -0
  9. package/dist/bin.d.ts +2 -0
  10. package/dist/bin.d.ts.map +1 -0
  11. package/dist/bin.js +56 -0
  12. package/dist/bin.js.map +1 -0
  13. package/dist/bsky.d.ts +27 -0
  14. package/dist/bsky.d.ts.map +1 -0
  15. package/dist/bsky.js +165 -0
  16. package/dist/bsky.js.map +1 -0
  17. package/dist/bsync.d.ts +22 -0
  18. package/dist/bsync.d.ts.map +1 -0
  19. package/dist/bsync.js +54 -0
  20. package/dist/bsync.js.map +1 -0
  21. package/dist/const.d.ts +4 -0
  22. package/dist/const.d.ts.map +1 -0
  23. package/dist/const.js +4 -0
  24. package/dist/const.js.map +1 -0
  25. package/dist/env.d.ts +2 -0
  26. package/dist/env.d.ts.map +1 -0
  27. package/dist/env.js +10 -0
  28. package/dist/env.js.map +1 -0
  29. package/dist/feed-gen.d.ts +15 -0
  30. package/dist/feed-gen.d.ts.map +1 -0
  31. package/dist/feed-gen.js +73 -0
  32. package/dist/feed-gen.js.map +1 -0
  33. package/dist/index.d.ts +17 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +17 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/introspect.d.ts +22 -0
  38. package/dist/introspect.d.ts.map +1 -0
  39. package/dist/introspect.js +65 -0
  40. package/dist/introspect.js.map +1 -0
  41. package/dist/mock/data.d.ts +3 -0
  42. package/dist/mock/data.d.ts.map +1 -0
  43. package/dist/mock/data.js +46 -0
  44. package/dist/mock/data.js.map +1 -0
  45. package/dist/mock/img/blur-hash-avatar-b64.d.ts +3 -0
  46. package/dist/mock/img/blur-hash-avatar-b64.d.ts.map +1 -0
  47. package/dist/mock/img/blur-hash-avatar-b64.js +2 -0
  48. package/dist/mock/img/blur-hash-avatar-b64.js.map +1 -0
  49. package/dist/mock/img/labeled-img-b64.d.ts +3 -0
  50. package/dist/mock/img/labeled-img-b64.d.ts.map +1 -0
  51. package/dist/mock/img/labeled-img-b64.js +2 -0
  52. package/dist/mock/img/labeled-img-b64.js.map +1 -0
  53. package/dist/mock/index.d.ts +3 -0
  54. package/dist/mock/index.d.ts.map +1 -0
  55. package/dist/mock/index.js +574 -0
  56. package/dist/mock/index.js.map +1 -0
  57. package/dist/moderator-client.d.ts +58 -0
  58. package/dist/moderator-client.d.ts.map +1 -0
  59. package/dist/moderator-client.js +110 -0
  60. package/dist/moderator-client.js.map +1 -0
  61. package/dist/network-no-appview.d.ts +21 -0
  62. package/dist/network-no-appview.d.ts.map +1 -0
  63. package/dist/network-no-appview.js +74 -0
  64. package/dist/network-no-appview.js.map +1 -0
  65. package/dist/network.d.ts +32 -0
  66. package/dist/network.d.ts.map +1 -0
  67. package/dist/network.js +190 -0
  68. package/dist/network.js.map +1 -0
  69. package/dist/ozone.d.ts +31 -0
  70. package/dist/ozone.d.ts.map +1 -0
  71. package/dist/ozone.js +254 -0
  72. package/dist/ozone.js.map +1 -0
  73. package/dist/pds.d.ts +23 -0
  74. package/dist/pds.d.ts.map +1 -0
  75. package/dist/pds.js +97 -0
  76. package/dist/pds.js.map +1 -0
  77. package/dist/plc.d.ts +14 -0
  78. package/dist/plc.d.ts.map +1 -0
  79. package/dist/plc.js +28 -0
  80. package/dist/plc.js.map +1 -0
  81. package/dist/seed/author-feed.d.ts +4 -0
  82. package/dist/seed/author-feed.d.ts.map +1 -0
  83. package/dist/seed/author-feed.js +50 -0
  84. package/dist/seed/author-feed.js.map +1 -0
  85. package/dist/seed/basic.d.ts +16 -0
  86. package/dist/seed/basic.d.ts.map +1 -0
  87. package/dist/seed/basic.js +113 -0
  88. package/dist/seed/basic.js.map +1 -0
  89. package/dist/seed/client.d.ts +151 -0
  90. package/dist/seed/client.d.ts.map +1 -0
  91. package/dist/seed/client.js +365 -0
  92. package/dist/seed/client.js.map +1 -0
  93. package/dist/seed/follows.d.ts +4 -0
  94. package/dist/seed/follows.d.ts.map +1 -0
  95. package/dist/seed/follows.js +55 -0
  96. package/dist/seed/follows.js.map +1 -0
  97. package/dist/seed/index.d.ts +11 -0
  98. package/dist/seed/index.d.ts.map +1 -0
  99. package/dist/seed/index.js +11 -0
  100. package/dist/seed/index.js.map +1 -0
  101. package/dist/seed/likes.d.ts +4 -0
  102. package/dist/seed/likes.d.ts.map +1 -0
  103. package/dist/seed/likes.js +37 -0
  104. package/dist/seed/likes.js.map +1 -0
  105. package/dist/seed/quotes.d.ts +4 -0
  106. package/dist/seed/quotes.d.ts.map +1 -0
  107. package/dist/seed/quotes.js +21 -0
  108. package/dist/seed/quotes.js.map +1 -0
  109. package/dist/seed/reposts.d.ts +4 -0
  110. package/dist/seed/reposts.d.ts.map +1 -0
  111. package/dist/seed/reposts.js +17 -0
  112. package/dist/seed/reposts.js.map +1 -0
  113. package/dist/seed/thread-v2.d.ts +227 -0
  114. package/dist/seed/thread-v2.d.ts.map +1 -0
  115. package/dist/seed/thread-v2.js +755 -0
  116. package/dist/seed/thread-v2.js.map +1 -0
  117. package/dist/seed/users-bulk.d.ts +3 -0
  118. package/dist/seed/users-bulk.d.ts.map +1 -0
  119. package/dist/seed/users-bulk.js +224 -0
  120. package/dist/seed/users-bulk.js.map +1 -0
  121. package/dist/seed/users.d.ts +3 -0
  122. package/dist/seed/users.d.ts.map +1 -0
  123. package/dist/seed/users.js +45 -0
  124. package/dist/seed/users.js.map +1 -0
  125. package/dist/seed/verifications.d.ts +5 -0
  126. package/dist/seed/verifications.d.ts.map +1 -0
  127. package/dist/seed/verifications.js +164 -0
  128. package/dist/seed/verifications.js.map +1 -0
  129. package/dist/service-profile-lexicon.d.ts +11 -0
  130. package/dist/service-profile-lexicon.d.ts.map +1 -0
  131. package/dist/service-profile-lexicon.js +115 -0
  132. package/dist/service-profile-lexicon.js.map +1 -0
  133. package/dist/service-profile-ozone.d.ts +18 -0
  134. package/dist/service-profile-ozone.d.ts.map +1 -0
  135. package/dist/service-profile-ozone.js +333 -0
  136. package/dist/service-profile-ozone.js.map +1 -0
  137. package/dist/service-profile.d.ts +24 -0
  138. package/dist/service-profile.d.ts.map +1 -0
  139. package/dist/service-profile.js +61 -0
  140. package/dist/service-profile.js.map +1 -0
  141. package/dist/types.d.ts +61 -0
  142. package/dist/types.d.ts.map +1 -0
  143. package/dist/types.js +2 -0
  144. package/dist/types.js.map +1 -0
  145. package/dist/util.d.ts +14 -0
  146. package/dist/util.d.ts.map +1 -0
  147. package/dist/util.js +86 -0
  148. package/dist/util.js.map +1 -0
  149. package/package.json +69 -0
  150. package/src/bin-multi-pds.ts +166 -0
  151. package/src/bin.ts +64 -0
  152. package/src/bsky.ts +198 -0
  153. package/src/bsync.ts +66 -0
  154. package/src/const.ts +3 -0
  155. package/src/env.ts +9 -0
  156. package/src/feed-gen.ts +96 -0
  157. package/src/index.ts +17 -0
  158. package/src/introspect.ts +91 -0
  159. package/src/mock/data.ts +46 -0
  160. package/src/mock/img/blur-hash-avatar-b64.ts +1 -0
  161. package/src/mock/img/labeled-img-b64.ts +1 -0
  162. package/src/mock/index.ts +702 -0
  163. package/src/moderator-client.ts +267 -0
  164. package/src/network-no-appview.ts +89 -0
  165. package/src/network.ts +243 -0
  166. package/src/ozone.ts +287 -0
  167. package/src/pds.ts +118 -0
  168. package/src/plc.ts +33 -0
  169. package/src/seed/author-feed.ts +98 -0
  170. package/src/seed/basic.ts +189 -0
  171. package/src/seed/client.ts +676 -0
  172. package/src/seed/follows.ts +57 -0
  173. package/src/seed/index.ts +11 -0
  174. package/src/seed/likes.ts +43 -0
  175. package/src/seed/quotes.ts +53 -0
  176. package/src/seed/reposts.ts +18 -0
  177. package/src/seed/thread-v2.ts +925 -0
  178. package/src/seed/users-bulk.ts +229 -0
  179. package/src/seed/users.ts +64 -0
  180. package/src/seed/verifications.ts +254 -0
  181. package/src/service-profile-lexicon.ts +127 -0
  182. package/src/service-profile-ozone.ts +375 -0
  183. package/src/service-profile.ts +95 -0
  184. package/src/types.ts +68 -0
  185. package/src/util.ts +118 -0
  186. package/tsconfig.build.json +25 -0
  187. 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
+ [![NPM](https://img.shields.io/npm/v/@atproto/dev-env)](https://www.npmjs.com/package/@atproto/dev-env)
6
+ [![Github CI Status](https://github.com/bluesky-social/atproto/actions/workflows/repo.yaml/badge.svg)](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,7 @@
1
+ #!/usr/bin/env node
2
+
3
+ // @NOTE This file exists so that pnpm can properly link the "bin" scripts when
4
+ // the monorepo is being setup (during initial "pnpm install"), but was never
5
+ // built.
6
+
7
+ import './dist/bin.js'
@@ -0,0 +1,2 @@
1
+ import './env.js';
2
+ //# sourceMappingURL=bin-multi-pds.d.ts.map
@@ -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,2 @@
1
+ import './env.js';
2
+ //# sourceMappingURL=bin.d.ts.map
@@ -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
@@ -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
@@ -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"]}
@@ -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"]}
@@ -0,0 +1,4 @@
1
+ export declare const ADMIN_PASSWORD = "admin-pass";
2
+ export declare const JWT_SECRET = "jwt-secret";
3
+ export declare const EXAMPLE_LABELER = "did:example:labeler";
4
+ //# sourceMappingURL=const.d.ts.map
@@ -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,4 @@
1
+ export const ADMIN_PASSWORD = 'admin-pass';
2
+ export const JWT_SECRET = 'jwt-secret';
3
+ export const EXAMPLE_LABELER = 'did:example:labeler';
4
+ //# sourceMappingURL=const.js.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=env.d.ts.map
@@ -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