@hypercerts-org/sdk-core 0.10.0-beta.0 → 0.10.0-beta.1

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 ADDED
@@ -0,0 +1,273 @@
1
+ # @hypercerts-org/sdk-core
2
+
3
+ ## 1.0.0-beta.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#66](https://github.com/hypercerts-org/hypercerts-sdk/pull/66)
8
+ [`7c33673`](https://github.com/hypercerts-org/hypercerts-sdk/commit/7c33673fd5f53d92ba160ced1d1582178fa7c455) Thanks
9
+ [@aspiers](https://github.com/aspiers)! - feat: migrate to published @hypercerts-org/lexicon package
10
+
11
+ This release migrates the SDK from using a local `packages/lexicon` workspace to consuming the published
12
+ `@hypercerts-org/lexicon` package from npm.
13
+
14
+ **Benefits:**
15
+ - **Single source of truth**: Lexicon definitions now come from a dedicated, independently versioned package
16
+ - **Reduced codebase**: Removes ~3,000 lines of duplicated lexicon code from this repository
17
+ - **Better versioning**: Lexicon can be updated independently via semver dependency updates
18
+ - **Simplified architecture**: No longer maintaining duplicate lexicon tooling in monorepo
19
+ - **Improved maintainability**: Clearer separation of concerns between SDK and lexicon definitions
20
+
21
+ **Breaking Changes:**
22
+ 1. **Removed `LexiconRegistry` class**: Use the `validate()` function instead
23
+ 2. **Removed `ValidationResult` type**: Validation functions now throw errors on validation failure
24
+ 3. **Renamed type exports** to match lexicon package conventions:
25
+ - `OrgHypercertsClaim` → `OrgHypercertsClaimActivity`
26
+ - `OrgHypercertsCollection` → `OrgHypercertsClaimCollection`
27
+ 4. **Renamed constant exports** to use consistent naming:
28
+ - `schemas` → `HYPERCERTS_SCHEMAS`
29
+ - `schemaDict` → `HYPERCERTS_SCHEMA_DICT`
30
+ - `ids` → `HYPERCERTS_NSIDS`
31
+ - `lexicons` now exported as type-only (use `HYPERCERTS_LEXICON_JSON` or `HYPERCERTS_LEXICON_DOC` for runtime
32
+ values)
33
+
34
+ **Migration Guide:**
35
+
36
+ **Validation:**
37
+
38
+ ```typescript
39
+ // Before
40
+ import { LexiconRegistry, HYPERCERT_LEXICONS, HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";
41
+ const registry = new LexiconRegistry();
42
+ registry.registerLexicons(HYPERCERT_LEXICONS);
43
+ const result = registry.validate(HYPERCERT_COLLECTIONS.CLAIM, claimData);
44
+ if (!result.valid) {
45
+ console.error("Invalid record:", result.error);
46
+ }
47
+
48
+ // After
49
+ import { validate, HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";
50
+ try {
51
+ validate(HYPERCERT_COLLECTIONS.CLAIM, claimData);
52
+ } catch (error) {
53
+ console.error("Invalid record:", error);
54
+ }
55
+ ```
56
+
57
+ **Type imports:**
58
+
59
+ ```typescript
60
+ // Before
61
+ import { OrgHypercertsClaim, OrgHypercertsCollection } from "@hypercerts-org/sdk-core";
62
+
63
+ // After
64
+ import { OrgHypercertsClaimActivity, OrgHypercertsClaimCollection } from "@hypercerts-org/sdk-core";
65
+ ```
66
+
67
+ **Constant imports:**
68
+
69
+ ```typescript
70
+ // Before
71
+ import { schemas, schemaDict, ids } from "@hypercerts-org/sdk-core";
72
+
73
+ // After
74
+ import { HYPERCERTS_SCHEMAS, HYPERCERTS_SCHEMA_DICT, HYPERCERTS_NSIDS } from "@hypercerts-org/sdk-core";
75
+ ```
76
+
77
+ **Other Changes:**
78
+ - Added dependency on `@hypercerts-org/lexicon@0.10.0-beta.3`
79
+ - Updated all lexicon type exports to use namespaced imports from lexicon package
80
+ - Improved hypercert validation with new test coverage
81
+ - Enhanced test mocks and fixtures for better testability
82
+
83
+ **For SDK users**: If you're using `LexiconRegistry`, follow the migration guide above. If you're only using the
84
+ high-level Repository API, no changes are required.
85
+
86
+ ### Minor Changes
87
+
88
+ - [#60](https://github.com/hypercerts-org/hypercerts-sdk/pull/60)
89
+ [`f7594f8`](https://github.com/hypercerts-org/hypercerts-sdk/commit/f7594f838fd7e64837da702f7498e84a49b28bf5) Thanks
90
+ [@bitbeckers](https://github.com/bitbeckers)! - Implement ConfigurableAgent for proper multi-server routing
91
+
92
+ This release introduces the `ConfigurableAgent` class that enables proper routing of AT Protocol requests to different
93
+ servers (PDS, SDS, or custom instances) while maintaining OAuth authentication from a single session.
94
+
95
+ **Breaking Changes:**
96
+ - Repository now uses `ConfigurableAgent` internally instead of standard `Agent`
97
+ - This fixes the issue where invalid `agent.service` and `agent.api.xrpc.uri` property assignments were causing
98
+ TypeScript errors
99
+
100
+ **New Features:**
101
+ - `ConfigurableAgent` class exported from `@hypercerts-org/sdk-core`
102
+ - Support for simultaneous connections to multiple SDS instances with one OAuth session
103
+ - Proper request routing based on configured service URL rather than session defaults
104
+
105
+ **Bug Fixes:**
106
+ - Remove invalid Agent property assignments that caused TypeScript compilation errors (TS2339)
107
+ - Replace all `any` types in test files with proper type annotations
108
+ - Eliminate build warnings from missing type declarations
109
+
110
+ **Architecture:** The new routing system wraps the OAuth session's fetch handler to prepend the target server URL,
111
+ ensuring requests go to the intended destination while maintaining full authentication (DPoP, access tokens, etc.).
112
+ This enables use cases like:
113
+ - Routing to SDS while authenticated via PDS
114
+ - Accessing multiple organization SDS instances simultaneously
115
+ - Testing against different server environments
116
+ - Dynamic switching between PDS and SDS operations
117
+
118
+ **Migration:** No action required - the change is transparent to existing code. The Repository API remains unchanged.
119
+
120
+ - [#46](https://github.com/hypercerts-org/hypercerts-sdk/pull/46)
121
+ [`eda4ac2`](https://github.com/hypercerts-org/hypercerts-sdk/commit/eda4ac233e09764d83f042ba7df94d4c9884cc01) Thanks
122
+ [@bitbeckers](https://github.com/bitbeckers)! - Initial release of sdk-core package with ATProto SDK for
123
+ authentication, repository operations, and lexicon management
124
+
125
+ - [#65](https://github.com/hypercerts-org/hypercerts-sdk/pull/65)
126
+ [`826b50c`](https://github.com/hypercerts-org/hypercerts-sdk/commit/826b50c140a56fee4feeb6b6c83d1123e44c5118) Thanks
127
+ [@bitbeckers](https://github.com/bitbeckers)! - feat(auth): add OAuth scopes and granular permissions system
128
+
129
+ Add comprehensive OAuth permissions system with support for granular permissions and easy email access:
130
+
131
+ **Permission System**
132
+ - Zod schemas for all ATProto permission types (account, repo, blob, rpc, identity, include)
133
+ - Support for both transitional (legacy) and granular permission models
134
+ - Type-safe permission builder with fluent API
135
+ - 14 pre-built scope presets (EMAIL_READ, POSTING_APP, FULL_ACCESS, etc.)
136
+ - 8 utility functions for working with scopes
137
+
138
+ **Email Access**
139
+ - New `getAccountEmail()` method to retrieve user email from authenticated session
140
+ - Returns null when permission not granted
141
+ - Comprehensive error handling
142
+
143
+ **Enhanced OAuth Integration**
144
+ - Automatic scope validation with helpful warnings
145
+ - Migration suggestions from transitional to granular permissions
146
+ - Improved documentation with comprehensive examples
147
+
148
+ **Breaking Changes**: None - fully backward compatible
149
+
150
+ **New Exports**:
151
+ - `PermissionBuilder` - Fluent API for building type-safe scopes
152
+ - `ScopePresets` - 14 ready-to-use permission presets
153
+ - Utility functions: `buildScope()`, `parseScope()`, `hasPermission()`, `validateScope()`, etc.
154
+ - Permission schemas and types for TypeScript consumers
155
+
156
+ See README for usage examples and migration guide.
157
+
158
+ - [#56](https://github.com/hypercerts-org/hypercerts-sdk/pull/56)
159
+ [`caceacb`](https://github.com/hypercerts-org/hypercerts-sdk/commit/caceacbc5572a590c750a95ccfda23fff2dd0c61) Thanks
160
+ [@bitbeckers](https://github.com/bitbeckers)! - Add pagination support and fix React hooks for SDS operations
161
+
162
+ **Breaking Changes (sdk-core):**
163
+ - `CollaboratorOperations.list()` now returns `{ collaborators: RepositoryAccessGrant[], cursor?: string }` instead of
164
+ `RepositoryAccessGrant[]`
165
+ - `OrganizationOperations.list()` now returns `{ organizations: OrganizationInfo[], cursor?: string }` instead of
166
+ `OrganizationInfo[]`
167
+
168
+ **Features:**
169
+ - Add cursor-based pagination support to collaborator and organization list operations
170
+ - Support optional `limit` and `cursor` parameters for paginated queries
171
+ - Update internal methods (`hasAccess`, `getRole`, `get`) to handle new pagination structure
172
+
173
+ **Bug Fixes (sdk-core):**
174
+ - Fix permissions parsing in `CollaboratorOperationsImpl.list()` to match actual SDS API format (object with boolean
175
+ flags)
176
+ - Prevent `TypeError: permissionArray.includes is not a function` by correctly handling permissions as objects
177
+ - Fix Agent service URL configuration to route queries to the correct server (PDS or SDS)
178
+ - Resolve "Could not find repo" errors when querying SDS repositories by ensuring Agent uses SDS service endpoint
179
+ - Update test mocks to use the actual SDS API response format
180
+
181
+ **Bug Fixes (sdk-react):**
182
+ - Fix `useCollaborators` hook to correctly destructure paginated response
183
+ - Fix `useOrganizations` hook to correctly destructure paginated response
184
+ - All React hooks now properly handle the new pagination structure
185
+
186
+ **Documentation:**
187
+ - Comprehensive README updates with clear examples for all SDK operations
188
+ - Added pagination examples throughout documentation
189
+ - Improved code samples with realistic use cases
190
+
191
+ **Tests:**
192
+ - All 317 tests passing (181 sdk-core + 136 sdk-react)
193
+ - Updated test mocks to match new pagination response structure
194
+ - Build completes with zero warnings
195
+
196
+ ### Patch Changes
197
+
198
+ - [#58](https://github.com/hypercerts-org/hypercerts-sdk/pull/58)
199
+ [`bcde5fa`](https://github.com/hypercerts-org/hypercerts-sdk/commit/bcde5faeb11dba6d99967a434e8ec32d67b3aca5) Thanks
200
+ [@bitbeckers](https://github.com/bitbeckers)! - Fix collaborator permissions parsing to align with SDS API response
201
+ format. The SDS API returns permissions as objects with boolean flags (`{ read: true, create: true, ... }`) rather
202
+ than string arrays. This fix simplifies the permissions parser to handle only the actual format returned by the API.
203
+
204
+ - [#64](https://github.com/hypercerts-org/hypercerts-sdk/pull/64)
205
+ [`f83f03a`](https://github.com/hypercerts-org/hypercerts-sdk/commit/f83f03a8e505d57d38b45f3a50213ca1035c1229) Thanks
206
+ [@bitbeckers](https://github.com/bitbeckers)! - fix(lexicon): correct field names and types to match lexicon schema
207
+ - Fix `workTimeframeFrom/To` -> `workTimeFrameFrom/To` (capital 'F' in Frame)
208
+ - Make `shortDescription` required for hypercert claims per lexicon schema
209
+ - Update all interfaces, implementations, and tests to use correct field names
210
+ - Add comprehensive lexicon documentation to README
211
+
212
+ - [#62](https://github.com/hypercerts-org/hypercerts-sdk/pull/62)
213
+ [`4b80edc`](https://github.com/hypercerts-org/hypercerts-sdk/commit/4b80edca4162c4ce929edb28ffffa3f99f21cb74) Thanks
214
+ [@bitbeckers](https://github.com/bitbeckers)! - fix(sdk-core): add required $type field to all record creation
215
+ operations
216
+
217
+ The AT Protocol requires all records to include a `$type` field, but the SDK was omitting it during record creation,
218
+ causing validation errors like "Record/$type must be a string". This fix:
219
+ - Adds `$type` field to all record types (rights, claims, locations, contributions, measurements, evaluations,
220
+ collections)
221
+ - Fixes location record implementation to match `app.certified.location` lexicon schema
222
+ - Makes `srs` (Spatial Reference System) field required for location records with proper validation
223
+ - Updates interfaces and documentation to reflect required fields
224
+
225
+ Breaking change: `location.srs` is now required when creating locations (use "EPSG:4326" for standard WGS84
226
+ coordinates).
227
+
228
+ - [#59](https://github.com/hypercerts-org/hypercerts-sdk/pull/59)
229
+ [`7020fcc`](https://github.com/hypercerts-org/hypercerts-sdk/commit/7020fcc9845a4d4c2f792536611fc3bb5e3c4fe3) Thanks
230
+ [@bitbeckers](https://github.com/bitbeckers)! - Configure npm publishing to exclude source code and development files.
231
+ Packages now only include the compiled `dist/` folder, README, and necessary runtime files (lexicon schemas). This
232
+ reduces package sizes and prevents unnecessary files from being published to npm.
233
+
234
+ - [#60](https://github.com/hypercerts-org/hypercerts-sdk/pull/60)
235
+ [`39accd9`](https://github.com/hypercerts-org/hypercerts-sdk/commit/39accd954422c901b7faf93e08be88e68a4f849a) Thanks
236
+ [@bitbeckers](https://github.com/bitbeckers)! - fix(sdk-core): ensure repository operations route to correct server
237
+ (PDS/SDS)
238
+
239
+ **Problem:** When using OAuth authentication to access organization repositories on SDS via
240
+ `repo.repo(organizationDid)`, all operations like `hypercerts.list()` and `hypercerts.listCollections()` were
241
+ incorrectly routing to the user's PDS instead of the SDS server, causing "Could not find repo" errors.
242
+
243
+ **Root Cause:** The AT Protocol Agent was created from the OAuth session but only had its `api.xrpc.uri` property
244
+ configured. Without setting the Agent's `service` property, it continued using the session's default PDS URL for all
245
+ requests, even when switched to organization repositories.
246
+
247
+ **Solution:** Set both `agent.service` and `agent.api.xrpc.uri` to the specified server URL in the Repository
248
+ constructor. This ensures that:
249
+ - Initial repository creation routes to the correct server (PDS or SDS)
250
+ - Repository switching via `.repo(did)` maintains the same server routing
251
+ - All operation implementations (HypercertOperationsImpl, RecordOperationsImpl, ProfileOperationsImpl,
252
+ BlobOperationsImpl) now route correctly
253
+
254
+ **Documentation:** Added comprehensive PDS/SDS orchestration explanation to README covering:
255
+ - Server type comparison and use cases
256
+ - How repository routing works internally
257
+ - Common patterns for personal vs organization hypercerts
258
+ - Key implementation details about Agent configuration
259
+
260
+ - [#56](https://github.com/hypercerts-org/hypercerts-sdk/pull/56)
261
+ [`cb3268d`](https://github.com/hypercerts-org/hypercerts-sdk/commit/cb3268d78614efaf15aecc57a5dc3bce8313f3ca) Thanks
262
+ [@bitbeckers](https://github.com/bitbeckers)! - Fix SDS organization and collaborator operations to match API
263
+ contracts
264
+ - Add required creatorDid parameter to organization.create endpoint
265
+ - Fix organization.list to parse organizations field instead of repositories
266
+ - Update accessType values to match SDS API: owner|shared|none (was owner|collaborator)
267
+ - Add permission string array parser for collaborator.list endpoint
268
+ - Update type definitions to match actual SDS API response formats
269
+
270
+ - [#55](https://github.com/hypercerts-org/hypercerts-sdk/pull/55)
271
+ [`23c3d9a`](https://github.com/hypercerts-org/hypercerts-sdk/commit/23c3d9a3b71f326df68b65420c83f7ae42c2432d) Thanks
272
+ [@bitbeckers](https://github.com/bitbeckers)! - Fix endpoints and NSIDs for SDS operations in CollaboratorOperations
273
+ and OrganizationOperations
package/README.md CHANGED
@@ -53,12 +53,14 @@ const claim = await repo.hypercerts.create({
53
53
  The SDK supports two types of AT Protocol servers:
54
54
 
55
55
  #### Personal Data Server (PDS)
56
+
56
57
  - **Purpose**: User's own data storage (e.g., Bluesky)
57
58
  - **Use case**: Individual hypercerts, personal records
58
59
  - **Features**: Profile management, basic CRUD operations
59
60
  - **Example**: `bsky.social`, any Bluesky PDS
60
61
 
61
62
  #### Shared Data Server (SDS)
63
+
62
64
  - **Purpose**: Collaborative data storage with access control
63
65
  - **Use case**: Organization hypercerts, team collaboration
64
66
  - **Features**: Organizations, multi-user access, role-based permissions
@@ -84,25 +86,27 @@ await orgRepo.hypercerts.list(); // Queries organization's hypercerts on SDS
84
86
  The SDK uses a `ConfigurableAgent` to route requests to different servers while maintaining your OAuth authentication:
85
87
 
86
88
  1. **Initial Repository Creation**
89
+
87
90
  ```typescript
88
91
  // User authenticates (OAuth session knows user's PDS)
89
92
  const session = await sdk.callback(params);
90
-
93
+
91
94
  // Create PDS repository - routes to user's PDS
92
95
  const pdsRepo = sdk.repository(session);
93
-
96
+
94
97
  // Create SDS repository - routes to SDS server
95
98
  const sdsRepo = sdk.repository(session, { server: "sds" });
96
99
  ```
97
100
 
98
101
  2. **Switching Repositories with `.repo()`**
102
+
99
103
  ```typescript
100
104
  // Start with user's SDS repository
101
105
  const userSdsRepo = sdk.repository(session, { server: "sds" });
102
-
106
+
103
107
  // Switch to organization's repository
104
108
  const orgRepo = userSdsRepo.repo("did:plc:org-did");
105
-
109
+
106
110
  // All operations on orgRepo still route to SDS, not user's PDS
107
111
  await orgRepo.hypercerts.list(); // ✅ Queries SDS
108
112
  await orgRepo.collaborators.list(); // ✅ Queries SDS
@@ -171,33 +175,34 @@ const repo = sdk.getRepository(session);
171
175
  Control exactly what your app can access using type-safe permission builders:
172
176
 
173
177
  ```typescript
174
- import { PermissionBuilder, ScopePresets, buildScope } from '@hypercerts-org/sdk-core';
178
+ import { PermissionBuilder, ScopePresets, buildScope } from "@hypercerts-org/sdk-core";
175
179
 
176
180
  // Use ready-made presets
177
- const scope = ScopePresets.EMAIL_AND_PROFILE; // Request email + profile access
178
- const scope = ScopePresets.POSTING_APP; // Full posting capabilities
181
+ const scope = ScopePresets.EMAIL_AND_PROFILE; // Request email + profile access
182
+ const scope = ScopePresets.POSTING_APP; // Full posting capabilities
179
183
 
180
184
  // Or build custom permissions
181
185
  const scope = buildScope(
182
186
  new PermissionBuilder()
183
- .accountEmail('read') // Read user's email
184
- .repoWrite('app.bsky.feed.post') // Create/update posts
185
- .blob(['image/*', 'video/*']) // Upload media
186
- .build()
187
+ .accountEmail("read") // Read user's email
188
+ .repoWrite("app.bsky.feed.post") // Create/update posts
189
+ .blob(["image/*", "video/*"]) // Upload media
190
+ .build(),
187
191
  );
188
192
 
189
193
  // Use in OAuth configuration
190
194
  const sdk = createATProtoSDK({
191
195
  oauth: {
192
- clientId: 'your-client-id',
193
- redirectUri: 'https://your-app.com/callback',
194
- scope: scope, // Your custom scope
196
+ clientId: "your-client-id",
197
+ redirectUri: "https://your-app.com/callback",
198
+ scope: scope, // Your custom scope
195
199
  // ... other config
196
- }
200
+ },
197
201
  });
198
202
  ```
199
203
 
200
204
  **Available Presets:**
205
+
201
206
  - `EMAIL_READ` - User's email address
202
207
  - `PROFILE_READ` / `PROFILE_WRITE` - Profile access
203
208
  - `POST_WRITE` - Create posts
@@ -218,7 +223,7 @@ const hypercert = await repo.hypercerts.create({
218
223
  description: "Research on carbon capture technologies",
219
224
  image: imageBlob, // optional: File or Blob
220
225
  externalUrl: "https://example.com/project",
221
-
226
+
222
227
  impact: {
223
228
  scope: ["Climate Change", "Carbon Capture"],
224
229
  work: {
@@ -227,7 +232,7 @@ const hypercert = await repo.hypercerts.create({
227
232
  },
228
233
  contributors: ["did:plc:researcher1", "did:plc:researcher2"],
229
234
  },
230
-
235
+
231
236
  rights: {
232
237
  license: "CC-BY-4.0",
233
238
  allowsDerivatives: true,
@@ -242,9 +247,7 @@ console.log("Created hypercert:", hypercert.uri);
242
247
 
243
248
  ```typescript
244
249
  // Get a specific hypercert by URI
245
- const hypercert = await repo.hypercerts.get(
246
- "at://did:plc:user123/org.hypercerts.claim/abc123"
247
- );
250
+ const hypercert = await repo.hypercerts.get("at://did:plc:user123/org.hypercerts.claim/abc123");
248
251
 
249
252
  // List all hypercerts in the repository
250
253
  const { records } = await repo.hypercerts.list();
@@ -263,26 +266,21 @@ if (cursor) {
263
266
 
264
267
  ```typescript
265
268
  // Update an existing hypercert
266
- await repo.hypercerts.update(
267
- "at://did:plc:user123/org.hypercerts.claim/abc123",
268
- {
269
- title: "Updated Climate Research Project",
270
- description: "Expanded scope to include renewable energy",
271
- impact: {
272
- scope: ["Climate Change", "Carbon Capture", "Renewable Energy"],
273
- work: { from: "2024-01-01", to: "2026-12-31" },
274
- contributors: ["did:plc:researcher1", "did:plc:researcher2"],
275
- },
276
- }
277
- );
269
+ await repo.hypercerts.update("at://did:plc:user123/org.hypercerts.claim/abc123", {
270
+ title: "Updated Climate Research Project",
271
+ description: "Expanded scope to include renewable energy",
272
+ impact: {
273
+ scope: ["Climate Change", "Carbon Capture", "Renewable Energy"],
274
+ work: { from: "2024-01-01", to: "2026-12-31" },
275
+ contributors: ["did:plc:researcher1", "did:plc:researcher2"],
276
+ },
277
+ });
278
278
  ```
279
279
 
280
280
  #### Deleting a Hypercert
281
281
 
282
282
  ```typescript
283
- await repo.hypercerts.delete(
284
- "at://did:plc:user123/org.hypercerts.claim/abc123"
285
- );
283
+ await repo.hypercerts.delete("at://did:plc:user123/org.hypercerts.claim/abc123");
286
284
  ```
287
285
 
288
286
  ### 4. Contributions and Measurements
@@ -323,10 +321,7 @@ const blobResult = await repo.blobs.upload(imageFile);
323
321
  console.log("Blob uploaded:", blobResult.ref.$link);
324
322
 
325
323
  // Download a blob
326
- const blobData = await repo.blobs.get(
327
- "did:plc:user123",
328
- "bafyreiabc123..."
329
- );
324
+ const blobData = await repo.blobs.get("did:plc:user123", "bafyreiabc123...");
330
325
  ```
331
326
 
332
327
  ### 6. Organizations (SDS only)
@@ -491,40 +486,40 @@ await repo.profile.update({
491
486
 
492
487
  ### Repository Operations
493
488
 
494
- | Operation | Method | PDS | SDS | Returns |
495
- |-----------|--------|-----|-----|---------|
496
- | **Records** | | | | |
497
- | Create record | `repo.records.create()` | ✅ | ✅ | `{ uri, cid }` |
498
- | Get record | `repo.records.get()` | ✅ | ✅ | Record data |
499
- | Update record | `repo.records.update()` | ✅ | ✅ | `{ uri, cid }` |
500
- | Delete record | `repo.records.delete()` | ✅ | ✅ | void |
501
- | List records | `repo.records.list()` | ✅ | ✅ | `{ records, cursor? }` |
502
- | **Hypercerts** | | | | |
503
- | Create hypercert | `repo.hypercerts.create()` | ✅ | ✅ | `{ uri, cid, value }` |
504
- | Get hypercert | `repo.hypercerts.get()` | ✅ | ✅ | Full hypercert |
505
- | Update hypercert | `repo.hypercerts.update()` | ✅ | ✅ | `{ uri, cid }` |
506
- | Delete hypercert | `repo.hypercerts.delete()` | ✅ | ✅ | void |
507
- | List hypercerts | `repo.hypercerts.list()` | ✅ | ✅ | `{ records, cursor? }` |
508
- | Add contribution | `repo.hypercerts.addContribution()` | ✅ | ✅ | Contribution |
509
- | Add measurement | `repo.hypercerts.addMeasurement()` | ✅ | ✅ | Measurement |
510
- | **Blobs** | | | | |
511
- | Upload blob | `repo.blobs.upload()` | ✅ | ✅ | `{ ref, mimeType, size }` |
512
- | Get blob | `repo.blobs.get()` | ✅ | ✅ | Blob data |
513
- | **Profile** | | | | |
514
- | Get profile | `repo.profile.get()` | ✅ | ❌ | Profile data |
515
- | Update profile | `repo.profile.update()` | ✅ | ❌ | void |
516
- | **Organizations** | | | | |
517
- | Create org | `repo.organizations.create()` | ❌ | ✅ | `{ did, name, ... }` |
518
- | Get org | `repo.organizations.get()` | ❌ | ✅ | Organization |
519
- | List orgs | `repo.organizations.list()` | ❌ | ✅ | `{ organizations, cursor? }` |
520
- | **Collaborators** | | | | |
521
- | Grant access | `repo.collaborators.grant()` | ❌ | ✅ | void |
522
- | Revoke access | `repo.collaborators.revoke()` | ❌ | ✅ | void |
523
- | List collaborators | `repo.collaborators.list()` | ❌ | ✅ | `{ collaborators, cursor? }` |
524
- | Check access | `repo.collaborators.hasAccess()` | ❌ | ✅ | boolean |
525
- | Get role | `repo.collaborators.getRole()` | ❌ | ✅ | Role string |
526
- | Get permissions | `repo.collaborators.getPermissions()` | ❌ | ✅ | Permissions |
527
- | Transfer ownership | `repo.collaborators.transferOwnership()` | ❌ | ✅ | void |
489
+ | Operation | Method | PDS | SDS | Returns |
490
+ | ------------------ | ---------------------------------------- | --- | --- | ---------------------------- |
491
+ | **Records** | | | | |
492
+ | Create record | `repo.records.create()` | ✅ | ✅ | `{ uri, cid }` |
493
+ | Get record | `repo.records.get()` | ✅ | ✅ | Record data |
494
+ | Update record | `repo.records.update()` | ✅ | ✅ | `{ uri, cid }` |
495
+ | Delete record | `repo.records.delete()` | ✅ | ✅ | void |
496
+ | List records | `repo.records.list()` | ✅ | ✅ | `{ records, cursor? }` |
497
+ | **Hypercerts** | | | | |
498
+ | Create hypercert | `repo.hypercerts.create()` | ✅ | ✅ | `{ uri, cid, value }` |
499
+ | Get hypercert | `repo.hypercerts.get()` | ✅ | ✅ | Full hypercert |
500
+ | Update hypercert | `repo.hypercerts.update()` | ✅ | ✅ | `{ uri, cid }` |
501
+ | Delete hypercert | `repo.hypercerts.delete()` | ✅ | ✅ | void |
502
+ | List hypercerts | `repo.hypercerts.list()` | ✅ | ✅ | `{ records, cursor? }` |
503
+ | Add contribution | `repo.hypercerts.addContribution()` | ✅ | ✅ | Contribution |
504
+ | Add measurement | `repo.hypercerts.addMeasurement()` | ✅ | ✅ | Measurement |
505
+ | **Blobs** | | | | |
506
+ | Upload blob | `repo.blobs.upload()` | ✅ | ✅ | `{ ref, mimeType, size }` |
507
+ | Get blob | `repo.blobs.get()` | ✅ | ✅ | Blob data |
508
+ | **Profile** | | | | |
509
+ | Get profile | `repo.profile.get()` | ✅ | ❌ | Profile data |
510
+ | Update profile | `repo.profile.update()` | ✅ | ❌ | void |
511
+ | **Organizations** | | | | |
512
+ | Create org | `repo.organizations.create()` | ❌ | ✅ | `{ did, name, ... }` |
513
+ | Get org | `repo.organizations.get()` | ❌ | ✅ | Organization |
514
+ | List orgs | `repo.organizations.list()` | ❌ | ✅ | `{ organizations, cursor? }` |
515
+ | **Collaborators** | | | | |
516
+ | Grant access | `repo.collaborators.grant()` | ❌ | ✅ | void |
517
+ | Revoke access | `repo.collaborators.revoke()` | ❌ | ✅ | void |
518
+ | List collaborators | `repo.collaborators.list()` | ❌ | ✅ | `{ collaborators, cursor? }` |
519
+ | Check access | `repo.collaborators.hasAccess()` | ❌ | ✅ | boolean |
520
+ | Get role | `repo.collaborators.getRole()` | ❌ | ✅ | Role string |
521
+ | Get permissions | `repo.collaborators.getPermissions()` | ❌ | ✅ | Permissions |
522
+ | Transfer ownership | `repo.collaborators.transferOwnership()` | ❌ | ✅ | void |
528
523
 
529
524
  ## Type System
530
525
 
@@ -549,15 +544,15 @@ if (OrgHypercertsClaim.isRecord(data)) {
549
544
  }
550
545
  ```
551
546
 
552
- | Lexicon Type | SDK Alias |
553
- |--------------|-----------|
554
- | `OrgHypercertsClaim.Main` | `HypercertClaim` |
555
- | `OrgHypercertsClaimRights.Main` | `HypercertRights` |
547
+ | Lexicon Type | SDK Alias |
548
+ | ------------------------------------- | ----------------------- |
549
+ | `OrgHypercertsClaim.Main` | `HypercertClaim` |
550
+ | `OrgHypercertsClaimRights.Main` | `HypercertRights` |
556
551
  | `OrgHypercertsClaimContribution.Main` | `HypercertContribution` |
557
- | `OrgHypercertsClaimMeasurement.Main` | `HypercertMeasurement` |
558
- | `OrgHypercertsClaimEvaluation.Main` | `HypercertEvaluation` |
559
- | `OrgHypercertsCollection.Main` | `HypercertCollection` |
560
- | `AppCertifiedLocation.Main` | `HypercertLocation` |
552
+ | `OrgHypercertsClaimMeasurement.Main` | `HypercertMeasurement` |
553
+ | `OrgHypercertsClaimEvaluation.Main` | `HypercertEvaluation` |
554
+ | `OrgHypercertsCollection.Main` | `HypercertCollection` |
555
+ | `AppCertifiedLocation.Main` | `HypercertLocation` |
561
556
 
562
557
  ## Error Handling
563
558
 
@@ -622,6 +617,7 @@ await sdsAgent.com.atproto.repo.listRecords({...});
622
617
  ```
623
618
 
624
619
  This is useful for:
620
+
625
621
  - Connecting to multiple SDS instances simultaneously
626
622
  - Testing against different server environments
627
623
  - Building tools that work across multiple organizations
@@ -655,7 +651,8 @@ await mockStore.set(mockSession);
655
651
 
656
652
  ### Working with Lexicons
657
653
 
658
- The SDK exports lexicon types and validation utilities from the `@hypercerts-org/lexicon` package for direct record manipulation and validation.
654
+ The SDK exports lexicon types and validation utilities from the `@hypercerts-org/lexicon` package for direct record
655
+ manipulation and validation.
659
656
 
660
657
  #### Lexicon Types
661
658
 
@@ -680,8 +677,8 @@ const claim: HypercertClaim = {
680
677
  shortDescription: "Urban garden serving 50 families", // REQUIRED
681
678
  description: "Detailed description...",
682
679
  workScope: "Food Security",
683
- workTimeFrameFrom: "2024-01-01T00:00:00Z", // Note: Capital 'F'
684
- workTimeFrameTo: "2024-12-31T00:00:00Z", // Note: Capital 'F'
680
+ workTimeFrameFrom: "2024-01-01T00:00:00Z", // Note: Capital 'F'
681
+ workTimeFrameTo: "2024-12-31T00:00:00Z", // Note: Capital 'F'
685
682
  rights: { uri: "at://...", cid: "..." },
686
683
  createdAt: new Date().toISOString(),
687
684
  };
@@ -692,16 +689,12 @@ const claim: HypercertClaim = {
692
689
  Validate records before creating them:
693
690
 
694
691
  ```typescript
695
- import {
696
- validate,
697
- OrgHypercertsClaim,
698
- HYPERCERT_COLLECTIONS,
699
- } from "@hypercerts-org/sdk-core";
692
+ import { validate, OrgHypercertsClaim, HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";
700
693
 
701
694
  // Validate using the lexicon package
702
695
  const validation = validate(
703
- HYPERCERT_COLLECTIONS.CLAIM, // "org.hypercerts.claim"
704
- claim
696
+ HYPERCERT_COLLECTIONS.CLAIM, // "org.hypercerts.claim"
697
+ claim,
705
698
  );
706
699
 
707
700
  if (!validation.valid) {
@@ -718,20 +711,13 @@ const validationResult = OrgHypercertsClaim.validateMain(claim);
718
711
  For repository-level validation:
719
712
 
720
713
  ```typescript
721
- import {
722
- LexiconRegistry,
723
- HYPERCERT_LEXICONS,
724
- HYPERCERT_COLLECTIONS,
725
- } from "@hypercerts-org/sdk-core";
714
+ import { LexiconRegistry, HYPERCERT_LEXICONS, HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";
726
715
 
727
716
  const registry = new LexiconRegistry();
728
717
  registry.registerLexicons(HYPERCERT_LEXICONS);
729
718
 
730
719
  // Validate a record
731
- const result = registry.validate(
732
- HYPERCERT_COLLECTIONS.CLAIM,
733
- claimData
734
- );
720
+ const result = registry.validate(HYPERCERT_COLLECTIONS.CLAIM, claimData);
735
721
 
736
722
  if (!result.valid) {
737
723
  console.error("Invalid record:", result.error);
@@ -741,10 +727,7 @@ if (!result.valid) {
741
727
  #### Creating Records with Proper Types
742
728
 
743
729
  ```typescript
744
- import type {
745
- HypercertContribution,
746
- StrongRef,
747
- } from "@hypercerts-org/sdk-core";
730
+ import type { HypercertContribution, StrongRef } from "@hypercerts-org/sdk-core";
748
731
  import { HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";
749
732
 
750
733
  // Create a contribution record
@@ -757,8 +740,8 @@ const contribution: HypercertContribution = {
757
740
  contributors: ["did:plc:contributor1", "did:plc:contributor2"],
758
741
  role: "implementer",
759
742
  description: "On-ground implementation team",
760
- workTimeframeFrom: "2024-01-01T00:00:00Z", // Note: lowercase 'f' for contributions
761
- workTimeframeTo: "2024-06-30T00:00:00Z", // Note: lowercase 'f' for contributions
743
+ workTimeframeFrom: "2024-01-01T00:00:00Z", // Note: lowercase 'f' for contributions
744
+ workTimeframeTo: "2024-06-30T00:00:00Z", // Note: lowercase 'f' for contributions
762
745
  createdAt: new Date().toISOString(),
763
746
  };
764
747
 
@@ -775,14 +758,14 @@ await repo.records.create({
775
758
  import { HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";
776
759
 
777
760
  // Collection NSIDs
778
- HYPERCERT_COLLECTIONS.CLAIM // "org.hypercerts.claim"
779
- HYPERCERT_COLLECTIONS.RIGHTS // "org.hypercerts.claim.rights"
780
- HYPERCERT_COLLECTIONS.CONTRIBUTION // "org.hypercerts.claim.contribution"
781
- HYPERCERT_COLLECTIONS.MEASUREMENT // "org.hypercerts.claim.measurement"
782
- HYPERCERT_COLLECTIONS.EVALUATION // "org.hypercerts.claim.evaluation"
783
- HYPERCERT_COLLECTIONS.EVIDENCE // "org.hypercerts.claim.evidence"
784
- HYPERCERT_COLLECTIONS.COLLECTION // "org.hypercerts.collection"
785
- HYPERCERT_COLLECTIONS.LOCATION // "app.certified.location"
761
+ HYPERCERT_COLLECTIONS.CLAIM; // "org.hypercerts.claim"
762
+ HYPERCERT_COLLECTIONS.RIGHTS; // "org.hypercerts.claim.rights"
763
+ HYPERCERT_COLLECTIONS.CONTRIBUTION; // "org.hypercerts.claim.contribution"
764
+ HYPERCERT_COLLECTIONS.MEASUREMENT; // "org.hypercerts.claim.measurement"
765
+ HYPERCERT_COLLECTIONS.EVALUATION; // "org.hypercerts.claim.evaluation"
766
+ HYPERCERT_COLLECTIONS.EVIDENCE; // "org.hypercerts.claim.evidence"
767
+ HYPERCERT_COLLECTIONS.COLLECTION; // "org.hypercerts.collection"
768
+ HYPERCERT_COLLECTIONS.LOCATION; // "app.certified.location"
786
769
  ```
787
770
 
788
771
  ## Development