@hypercerts-org/sdk-core 0.5.0-beta.0 → 0.7.0-beta.0

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 (57) hide show
  1. package/README.md +130 -8
  2. package/dist/index.cjs +93 -15
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +64 -1
  5. package/dist/index.mjs +93 -16
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +9 -5
  8. package/.turbo/turbo-build.log +0 -40
  9. package/.turbo/turbo-test.log +0 -119
  10. package/CHANGELOG.md +0 -62
  11. package/eslint.config.mjs +0 -22
  12. package/rollup.config.js +0 -75
  13. package/src/auth/OAuthClient.ts +0 -497
  14. package/src/core/SDK.ts +0 -410
  15. package/src/core/config.ts +0 -243
  16. package/src/core/errors.ts +0 -257
  17. package/src/core/interfaces.ts +0 -324
  18. package/src/core/types.ts +0 -282
  19. package/src/errors.ts +0 -57
  20. package/src/index.ts +0 -107
  21. package/src/lexicons.ts +0 -64
  22. package/src/repository/BlobOperationsImpl.ts +0 -199
  23. package/src/repository/CollaboratorOperationsImpl.ts +0 -442
  24. package/src/repository/HypercertOperationsImpl.ts +0 -1146
  25. package/src/repository/LexiconRegistry.ts +0 -332
  26. package/src/repository/OrganizationOperationsImpl.ts +0 -282
  27. package/src/repository/ProfileOperationsImpl.ts +0 -281
  28. package/src/repository/RecordOperationsImpl.ts +0 -340
  29. package/src/repository/Repository.ts +0 -482
  30. package/src/repository/interfaces.ts +0 -909
  31. package/src/repository/types.ts +0 -111
  32. package/src/services/hypercerts/types.ts +0 -87
  33. package/src/storage/InMemorySessionStore.ts +0 -127
  34. package/src/storage/InMemoryStateStore.ts +0 -146
  35. package/src/storage.ts +0 -63
  36. package/src/testing/index.ts +0 -67
  37. package/src/testing/mocks.ts +0 -142
  38. package/src/testing/stores.ts +0 -285
  39. package/src/testing.ts +0 -64
  40. package/src/types.ts +0 -86
  41. package/tests/auth/OAuthClient.test.ts +0 -164
  42. package/tests/core/SDK.test.ts +0 -176
  43. package/tests/core/errors.test.ts +0 -81
  44. package/tests/repository/BlobOperationsImpl.test.ts +0 -155
  45. package/tests/repository/CollaboratorOperationsImpl.test.ts +0 -438
  46. package/tests/repository/HypercertOperationsImpl.test.ts +0 -652
  47. package/tests/repository/LexiconRegistry.test.ts +0 -192
  48. package/tests/repository/OrganizationOperationsImpl.test.ts +0 -240
  49. package/tests/repository/ProfileOperationsImpl.test.ts +0 -254
  50. package/tests/repository/RecordOperationsImpl.test.ts +0 -375
  51. package/tests/repository/Repository.test.ts +0 -149
  52. package/tests/utils/fixtures.ts +0 -117
  53. package/tests/utils/mocks.ts +0 -109
  54. package/tests/utils/repository-fixtures.ts +0 -78
  55. package/tsconfig.json +0 -11
  56. package/tsconfig.tsbuildinfo +0 -1
  57. package/vitest.config.ts +0 -30
package/README.md CHANGED
@@ -44,7 +44,100 @@ const claim = await repo.hypercerts.create({
44
44
 
45
45
  ## Core Concepts
46
46
 
47
- ### 1. Authentication
47
+ ### 1. PDS vs SDS: Understanding Server Types
48
+
49
+ The SDK supports two types of AT Protocol servers:
50
+
51
+ #### Personal Data Server (PDS)
52
+ - **Purpose**: User's own data storage (e.g., Bluesky)
53
+ - **Use case**: Individual hypercerts, personal records
54
+ - **Features**: Profile management, basic CRUD operations
55
+ - **Example**: `bsky.social`, any Bluesky PDS
56
+
57
+ #### Shared Data Server (SDS)
58
+ - **Purpose**: Collaborative data storage with access control
59
+ - **Use case**: Organization hypercerts, team collaboration
60
+ - **Features**: Organizations, multi-user access, role-based permissions
61
+ - **Example**: `sds.hypercerts.org`
62
+
63
+ ```typescript
64
+ // Connect to user's PDS (default)
65
+ const pdsRepo = sdk.repository(session);
66
+ await pdsRepo.hypercerts.create({ ... }); // Creates in user's PDS
67
+
68
+ // Connect to SDS for collaboration features
69
+ const sdsRepo = sdk.repository(session, { server: "sds" });
70
+ await sdsRepo.organizations.create({ name: "My Org" }); // SDS-only feature
71
+
72
+ // Switch to organization repository (still on SDS)
73
+ const orgs = await sdsRepo.organizations.list();
74
+ const orgRepo = sdsRepo.repo(orgs.organizations[0].did);
75
+ await orgRepo.hypercerts.list(); // Queries organization's hypercerts on SDS
76
+ ```
77
+
78
+ #### How Repository Routing Works
79
+
80
+ The SDK uses a `ConfigurableAgent` to route requests to different servers while maintaining your OAuth authentication:
81
+
82
+ 1. **Initial Repository Creation**
83
+ ```typescript
84
+ // User authenticates (OAuth session knows user's PDS)
85
+ const session = await sdk.callback(params);
86
+
87
+ // Create PDS repository - routes to user's PDS
88
+ const pdsRepo = sdk.repository(session);
89
+
90
+ // Create SDS repository - routes to SDS server
91
+ const sdsRepo = sdk.repository(session, { server: "sds" });
92
+ ```
93
+
94
+ 2. **Switching Repositories with `.repo()`**
95
+ ```typescript
96
+ // Start with user's SDS repository
97
+ const userSdsRepo = sdk.repository(session, { server: "sds" });
98
+
99
+ // Switch to organization's repository
100
+ const orgRepo = userSdsRepo.repo("did:plc:org-did");
101
+
102
+ // All operations on orgRepo still route to SDS, not user's PDS
103
+ await orgRepo.hypercerts.list(); // ✅ Queries SDS
104
+ await orgRepo.collaborators.list(); // ✅ Queries SDS
105
+ ```
106
+
107
+ 3. **Key Implementation Details**
108
+ - Each Repository uses a `ConfigurableAgent` that wraps your OAuth session's fetch handler
109
+ - The agent routes all requests to the specified server URL (PDS, SDS, or custom)
110
+ - When you call `.repo(did)`, a new Repository is created with the same server configuration
111
+ - Your OAuth session provides authentication (DPoP, access tokens), while the agent handles routing
112
+ - This enables simultaneous connections to multiple servers with one authentication session
113
+
114
+ #### Common Patterns
115
+
116
+ ```typescript
117
+ // Pattern 1: Personal hypercerts on PDS
118
+ const myRepo = sdk.repository(session);
119
+ await myRepo.hypercerts.create({ title: "My Personal Impact" });
120
+
121
+ // Pattern 2: Organization hypercerts on SDS
122
+ const sdsRepo = sdk.repository(session, { server: "sds" });
123
+ const orgRepo = sdsRepo.repo(organizationDid);
124
+ await orgRepo.hypercerts.create({ title: "Team Impact" });
125
+
126
+ // Pattern 3: Reading another user's hypercerts
127
+ const otherUserRepo = myRepo.repo("did:plc:other-user");
128
+ await otherUserRepo.hypercerts.list(); // Read-only access to their PDS
129
+
130
+ // Pattern 4: Collaborating on organization data
131
+ const sdsRepo = sdk.repository(session, { server: "sds" });
132
+ await sdsRepo.collaborators.grant({
133
+ userDid: "did:plc:teammate",
134
+ role: "editor",
135
+ });
136
+ const orgRepo = sdsRepo.repo(organizationDid);
137
+ // Teammate can now access orgRepo and create hypercerts
138
+ ```
139
+
140
+ ### 2. Authentication
48
141
 
49
142
  The SDK uses OAuth 2.0 for authentication with support for both PDS (Personal Data Server) and SDS (Shared Data Server).
50
143
 
@@ -67,7 +160,7 @@ const session = await sdk.restoreSession("did:plc:user123");
67
160
  const repo = sdk.getRepository(session);
68
161
  ```
69
162
 
70
- ### 2. Working with Hypercerts
163
+ ### 3. Working with Hypercerts
71
164
 
72
165
  #### Creating a Hypercert
73
166
 
@@ -144,7 +237,7 @@ await repo.hypercerts.delete(
144
237
  );
145
238
  ```
146
239
 
147
- ### 3. Contributions and Measurements
240
+ ### 4. Contributions and Measurements
148
241
 
149
242
  #### Adding Contributions
150
243
 
@@ -174,7 +267,7 @@ const measurement = await repo.hypercerts.addMeasurement({
174
267
  });
175
268
  ```
176
269
 
177
- ### 4. Blob Operations (Images & Files)
270
+ ### 5. Blob Operations (Images & Files)
178
271
 
179
272
  ```typescript
180
273
  // Upload an image or file
@@ -188,7 +281,7 @@ const blobData = await repo.blobs.get(
188
281
  );
189
282
  ```
190
283
 
191
- ### 5. Organizations (SDS only)
284
+ ### 6. Organizations (SDS only)
192
285
 
193
286
  Organizations allow multiple users to collaborate on shared repositories.
194
287
 
@@ -216,7 +309,7 @@ const org = await repo.organizations.get("did:plc:org123");
216
309
  console.log(`${org.name} - ${org.description}`);
217
310
  ```
218
311
 
219
- ### 6. Collaborator Management (SDS only)
312
+ ### 7. Collaborator Management (SDS only)
220
313
 
221
314
  Manage who has access to your repository and what they can do.
222
315
 
@@ -285,7 +378,7 @@ await repo.collaborators.transferOwnership({
285
378
  });
286
379
  ```
287
380
 
288
- ### 7. Generic Record Operations
381
+ ### 8. Generic Record Operations
289
382
 
290
383
  For working with any ATProto record type:
291
384
 
@@ -330,7 +423,7 @@ const { records, cursor } = await repo.records.list({
330
423
  });
331
424
  ```
332
425
 
333
- ### 8. Profile Management (PDS only)
426
+ ### 9. Profile Management (PDS only)
334
427
 
335
428
  ```typescript
336
429
  // Get user profile
@@ -457,6 +550,35 @@ try {
457
550
 
458
551
  ## Advanced Usage
459
552
 
553
+ ### Multi-Server Routing with ConfigurableAgent
554
+
555
+ The `ConfigurableAgent` allows you to create custom agents that route to specific servers:
556
+
557
+ ```typescript
558
+ import { ConfigurableAgent } from "@hypercerts-org/sdk-core";
559
+
560
+ // Authenticate once with your PDS
561
+ const session = await sdk.callback(params);
562
+
563
+ // Create agents for different servers using the same session
564
+ const pdsAgent = new ConfigurableAgent(session, "https://bsky.social");
565
+ const sdsAgent = new ConfigurableAgent(session, "https://sds.hypercerts.org");
566
+ const orgAgent = new ConfigurableAgent(session, "https://sds-org-a.example.com");
567
+
568
+ // Use agents directly with AT Protocol APIs
569
+ await pdsAgent.com.atproto.repo.createRecord({...});
570
+ await sdsAgent.com.atproto.repo.listRecords({...});
571
+
572
+ // Or pass to Repository for high-level operations
573
+ // (Repository internally uses ConfigurableAgent)
574
+ ```
575
+
576
+ This is useful for:
577
+ - Connecting to multiple SDS instances simultaneously
578
+ - Testing against different server environments
579
+ - Building tools that work across multiple organizations
580
+ - Direct AT Protocol API access with custom routing
581
+
460
582
  ### Custom Session Storage
461
583
 
462
584
  ```typescript
package/dist/index.cjs CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  var oauthClientNode = require('@atproto/oauth-client-node');
4
4
  var lexicon$1 = require('@atproto/lexicon');
5
- var api = require('@atproto/api');
6
5
  var lexicon = require('@hypercerts-org/lexicon');
6
+ var api = require('@atproto/api');
7
7
  var eventemitter3 = require('eventemitter3');
8
8
  var zod = require('zod');
9
9
 
@@ -1246,6 +1246,80 @@ class LexiconRegistry {
1246
1246
  }
1247
1247
  }
1248
1248
 
1249
+ /**
1250
+ * ConfigurableAgent - Agent with configurable service URL routing.
1251
+ *
1252
+ * This module provides an Agent extension that allows routing requests to
1253
+ * a specific server URL, overriding the default URL from the OAuth session.
1254
+ *
1255
+ * @packageDocumentation
1256
+ */
1257
+ /**
1258
+ * Agent subclass that routes requests to a configurable service URL.
1259
+ *
1260
+ * The standard Agent uses the service URL embedded in the OAuth session's
1261
+ * fetch handler. This class allows overriding that URL to route requests
1262
+ * to different servers (e.g., PDS vs SDS, or multiple SDS instances).
1263
+ *
1264
+ * @remarks
1265
+ * This is particularly useful for:
1266
+ * - Routing to a Shared Data Server (SDS) while authenticated via PDS
1267
+ * - Supporting multiple SDS instances for different organizations
1268
+ * - Testing against different server environments
1269
+ *
1270
+ * @example Basic usage
1271
+ * ```typescript
1272
+ * const session = await sdk.authorize("user.bsky.social");
1273
+ *
1274
+ * // Create agent routing to SDS instead of session's default PDS
1275
+ * const sdsAgent = new ConfigurableAgent(session, "https://sds.hypercerts.org");
1276
+ *
1277
+ * // All requests will now go to the SDS
1278
+ * await sdsAgent.com.atproto.repo.createRecord({...});
1279
+ * ```
1280
+ *
1281
+ * @example Multiple SDS instances
1282
+ * ```typescript
1283
+ * // Route to organization A's SDS
1284
+ * const orgAAgent = new ConfigurableAgent(session, "https://sds-org-a.example.com");
1285
+ *
1286
+ * // Route to organization B's SDS
1287
+ * const orgBAgent = new ConfigurableAgent(session, "https://sds-org-b.example.com");
1288
+ * ```
1289
+ */
1290
+ class ConfigurableAgent extends api.Agent {
1291
+ /**
1292
+ * Creates a ConfigurableAgent that routes to a specific service URL.
1293
+ *
1294
+ * @param session - OAuth session for authentication
1295
+ * @param serviceUrl - Base URL of the server to route requests to
1296
+ *
1297
+ * @remarks
1298
+ * The agent wraps the session's fetch handler to intercept requests and
1299
+ * prepend the custom service URL instead of using the session's default.
1300
+ */
1301
+ constructor(session, serviceUrl) {
1302
+ // Create a custom fetch handler that uses our service URL
1303
+ const customFetchHandler = async (pathname, init) => {
1304
+ // Construct the full URL with our custom service
1305
+ const url = new URL(pathname, serviceUrl).toString();
1306
+ // Use the session's fetch handler for authentication (DPoP, etc.)
1307
+ return session.fetchHandler(url, init);
1308
+ };
1309
+ // Initialize the parent Agent with our custom fetch handler
1310
+ super(customFetchHandler);
1311
+ this.customServiceUrl = serviceUrl;
1312
+ }
1313
+ /**
1314
+ * Gets the service URL this agent routes to.
1315
+ *
1316
+ * @returns The base URL of the configured service
1317
+ */
1318
+ getServiceUrl() {
1319
+ return this.customServiceUrl;
1320
+ }
1321
+ }
1322
+
1249
1323
  /**
1250
1324
  * RecordOperationsImpl - Low-level record CRUD operations.
1251
1325
  *
@@ -3119,23 +3193,24 @@ class CollaboratorOperationsImpl {
3119
3193
  return "viewer";
3120
3194
  }
3121
3195
  /**
3122
- * Converts a permission string array to a permissions object.
3196
+ * Normalizes permissions from SDS API format to SDK format.
3123
3197
  *
3124
- * The SDS API returns permissions as an array of strings (e.g., ["read", "create"]).
3125
- * This method converts them to the boolean flag format used by the SDK.
3198
+ * The SDS API returns permissions as an object with boolean flags
3199
+ * (e.g., `{ read: true, create: true, update: false, ... }`).
3200
+ * This method ensures all expected fields are present with default values.
3126
3201
  *
3127
- * @param permissionArray - Array of permission strings from SDS API
3128
- * @returns Permission flags object
3202
+ * @param permissions - Permissions object from SDS API
3203
+ * @returns Normalized permission flags object
3129
3204
  * @internal
3130
3205
  */
3131
- parsePermissions(permissionArray) {
3206
+ parsePermissions(permissions) {
3132
3207
  return {
3133
- read: permissionArray.includes("read"),
3134
- create: permissionArray.includes("create"),
3135
- update: permissionArray.includes("update"),
3136
- delete: permissionArray.includes("delete"),
3137
- admin: permissionArray.includes("admin"),
3138
- owner: permissionArray.includes("owner"),
3208
+ read: permissions.read ?? false,
3209
+ create: permissions.create ?? false,
3210
+ update: permissions.update ?? false,
3211
+ delete: permissions.delete ?? false,
3212
+ admin: permissions.admin ?? false,
3213
+ owner: permissions.owner ?? false,
3139
3214
  };
3140
3215
  }
3141
3216
  /**
@@ -3771,8 +3846,10 @@ class Repository {
3771
3846
  this.lexiconRegistry = lexiconRegistry;
3772
3847
  this._isSDS = isSDS;
3773
3848
  this.logger = logger;
3774
- // Create Agent with OAuth session
3775
- this.agent = new api.Agent(session);
3849
+ // Create a ConfigurableAgent that routes requests to the specified server URL
3850
+ // This allows routing to PDS, SDS, or any custom server while maintaining
3851
+ // the OAuth session's authentication
3852
+ this.agent = new ConfigurableAgent(session, serverUrl);
3776
3853
  this.lexiconRegistry.addToAgent(this.agent);
3777
3854
  // Register hypercert lexicons
3778
3855
  this.lexiconRegistry.registerMany(lexicon.HYPERCERT_LEXICONS);
@@ -4692,6 +4769,7 @@ exports.ATProtoSDKError = ATProtoSDKError;
4692
4769
  exports.AuthenticationError = AuthenticationError;
4693
4770
  exports.CollaboratorPermissionsSchema = CollaboratorPermissionsSchema;
4694
4771
  exports.CollaboratorSchema = CollaboratorSchema;
4772
+ exports.ConfigurableAgent = ConfigurableAgent;
4695
4773
  exports.InMemorySessionStore = InMemorySessionStore;
4696
4774
  exports.InMemoryStateStore = InMemoryStateStore;
4697
4775
  exports.LexiconRegistry = LexiconRegistry;