@hypercerts-org/sdk-core 0.4.0-beta.0 → 0.6.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.
- package/README.md +459 -79
- package/dist/index.cjs +128 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +28 -9
- package/dist/index.mjs +128 -47
- package/dist/index.mjs.map +1 -1
- package/dist/types.cjs +3 -2
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.ts +28 -9
- package/dist/types.mjs +3 -2
- package/dist/types.mjs.map +1 -1
- package/package.json +9 -5
- package/.turbo/turbo-build.log +0 -328
- package/.turbo/turbo-test.log +0 -118
- package/CHANGELOG.md +0 -22
- package/eslint.config.mjs +0 -22
- package/rollup.config.js +0 -75
- package/src/auth/OAuthClient.ts +0 -497
- package/src/core/SDK.ts +0 -410
- package/src/core/config.ts +0 -243
- package/src/core/errors.ts +0 -257
- package/src/core/interfaces.ts +0 -324
- package/src/core/types.ts +0 -281
- package/src/errors.ts +0 -57
- package/src/index.ts +0 -107
- package/src/lexicons.ts +0 -64
- package/src/repository/BlobOperationsImpl.ts +0 -199
- package/src/repository/CollaboratorOperationsImpl.ts +0 -396
- package/src/repository/HypercertOperationsImpl.ts +0 -1146
- package/src/repository/LexiconRegistry.ts +0 -332
- package/src/repository/OrganizationOperationsImpl.ts +0 -234
- package/src/repository/ProfileOperationsImpl.ts +0 -281
- package/src/repository/RecordOperationsImpl.ts +0 -340
- package/src/repository/Repository.ts +0 -482
- package/src/repository/interfaces.ts +0 -897
- package/src/repository/types.ts +0 -111
- package/src/services/hypercerts/types.ts +0 -87
- package/src/storage/InMemorySessionStore.ts +0 -127
- package/src/storage/InMemoryStateStore.ts +0 -146
- package/src/storage.ts +0 -63
- package/src/testing/index.ts +0 -67
- package/src/testing/mocks.ts +0 -142
- package/src/testing/stores.ts +0 -285
- package/src/testing.ts +0 -64
- package/src/types.ts +0 -86
- package/tests/auth/OAuthClient.test.ts +0 -164
- package/tests/core/SDK.test.ts +0 -176
- package/tests/core/errors.test.ts +0 -81
- package/tests/repository/BlobOperationsImpl.test.ts +0 -154
- package/tests/repository/CollaboratorOperationsImpl.test.ts +0 -438
- package/tests/repository/HypercertOperationsImpl.test.ts +0 -652
- package/tests/repository/LexiconRegistry.test.ts +0 -192
- package/tests/repository/OrganizationOperationsImpl.test.ts +0 -242
- package/tests/repository/ProfileOperationsImpl.test.ts +0 -254
- package/tests/repository/RecordOperationsImpl.test.ts +0 -375
- package/tests/repository/Repository.test.ts +0 -149
- package/tests/utils/fixtures.ts +0 -117
- package/tests/utils/mocks.ts +0 -109
- package/tests/utils/repository-fixtures.ts +0 -78
- package/tsconfig.json +0 -11
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -30
package/README.md
CHANGED
|
@@ -1,54 +1,17 @@
|
|
|
1
1
|
# @hypercerts-org/sdk-core
|
|
2
2
|
|
|
3
|
-
Framework-agnostic ATProto SDK for Hypercerts.
|
|
3
|
+
Framework-agnostic ATProto SDK for Hypercerts. Create, manage, and collaborate on hypercerts using the AT Protocol.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
pnpm add @hypercerts-org/sdk-core
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
@hypercerts-org/sdk-core
|
|
13
|
-
├── / → Full SDK (createATProtoSDK, Repository, types, errors)
|
|
14
|
-
├── /types → TypeScript types (re-exported from @hypercerts-org/lexicon)
|
|
15
|
-
├── /errors → Error classes
|
|
16
|
-
├── /lexicons → LexiconRegistry, HYPERCERT_LEXICONS, HYPERCERT_COLLECTIONS
|
|
17
|
-
├── /storage → InMemorySessionStore, InMemoryStateStore
|
|
18
|
-
└── /testing → createMockSession, MockSessionStore
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Type System
|
|
22
|
-
|
|
23
|
-
Types are generated from ATProto lexicon definitions in `@hypercerts-org/lexicon` and re-exported with friendly aliases:
|
|
24
|
-
|
|
25
|
-
| Lexicon Type | SDK Alias |
|
|
26
|
-
|--------------|-----------|
|
|
27
|
-
| `OrgHypercertsClaim.Main` | `HypercertClaim` |
|
|
28
|
-
| `OrgHypercertsClaimRights.Main` | `HypercertRights` |
|
|
29
|
-
| `OrgHypercertsClaimContribution.Main` | `HypercertContribution` |
|
|
30
|
-
| `OrgHypercertsClaimMeasurement.Main` | `HypercertMeasurement` |
|
|
31
|
-
| `OrgHypercertsClaimEvaluation.Main` | `HypercertEvaluation` |
|
|
32
|
-
| `OrgHypercertsCollection.Main` | `HypercertCollection` |
|
|
33
|
-
| `AppCertifiedLocation.Main` | `HypercertLocation` |
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
import type { HypercertClaim, HypercertRights } from "@hypercerts-org/sdk-core";
|
|
37
|
-
|
|
38
|
-
// For validation functions, import the namespaced types
|
|
39
|
-
import { OrgHypercertsClaim } from "@hypercerts-org/sdk-core";
|
|
40
|
-
|
|
41
|
-
if (OrgHypercertsClaim.isRecord(data)) {
|
|
42
|
-
// data is typed as HypercertClaim
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Usage
|
|
9
|
+
## Quick Start
|
|
47
10
|
|
|
48
11
|
```typescript
|
|
49
12
|
import { createATProtoSDK } from "@hypercerts-org/sdk-core";
|
|
50
13
|
|
|
51
|
-
// 1. Create SDK
|
|
14
|
+
// 1. Create SDK with OAuth configuration
|
|
52
15
|
const sdk = createATProtoSDK({
|
|
53
16
|
oauth: {
|
|
54
17
|
clientId: "https://your-app.com/client-metadata.json",
|
|
@@ -59,85 +22,502 @@ const sdk = createATProtoSDK({
|
|
|
59
22
|
},
|
|
60
23
|
});
|
|
61
24
|
|
|
62
|
-
// 2.
|
|
25
|
+
// 2. Authenticate user
|
|
63
26
|
const authUrl = await sdk.authorize("user.bsky.social");
|
|
27
|
+
// Redirect user to authUrl...
|
|
28
|
+
|
|
29
|
+
// 3. Handle OAuth callback
|
|
30
|
+
const session = await sdk.callback(callbackParams);
|
|
31
|
+
|
|
32
|
+
// 4. Get repository and start creating hypercerts
|
|
33
|
+
const repo = sdk.getRepository(session);
|
|
34
|
+
const claim = await repo.hypercerts.create({
|
|
35
|
+
title: "Tree Planting Initiative 2025",
|
|
36
|
+
description: "Planted 1000 trees in the rainforest",
|
|
37
|
+
impact: {
|
|
38
|
+
scope: ["Environmental Conservation"],
|
|
39
|
+
work: { from: "2025-01-01", to: "2025-12-31" },
|
|
40
|
+
contributors: ["did:plc:contributor1"],
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Core Concepts
|
|
46
|
+
|
|
47
|
+
### 1. Authentication
|
|
48
|
+
|
|
49
|
+
The SDK uses OAuth 2.0 for authentication with support for both PDS (Personal Data Server) and SDS (Shared Data Server).
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// First-time user authentication
|
|
53
|
+
const authUrl = await sdk.authorize("user.bsky.social");
|
|
54
|
+
// Redirect user to authUrl to complete OAuth flow
|
|
55
|
+
|
|
56
|
+
// Handle the OAuth callback
|
|
57
|
+
const session = await sdk.callback({
|
|
58
|
+
code: "...",
|
|
59
|
+
state: "...",
|
|
60
|
+
iss: "...",
|
|
61
|
+
});
|
|
64
62
|
|
|
65
|
-
//
|
|
66
|
-
const session = await sdk.
|
|
63
|
+
// Restore existing session for returning users
|
|
64
|
+
const session = await sdk.restoreSession("did:plc:user123");
|
|
67
65
|
|
|
68
|
-
//
|
|
66
|
+
// Get repository for authenticated user
|
|
69
67
|
const repo = sdk.getRepository(session);
|
|
70
|
-
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Working with Hypercerts
|
|
71
|
+
|
|
72
|
+
#### Creating a Hypercert
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const hypercert = await repo.hypercerts.create({
|
|
76
|
+
title: "Climate Research Project",
|
|
77
|
+
description: "Research on carbon capture technologies",
|
|
78
|
+
image: imageBlob, // optional: File or Blob
|
|
79
|
+
externalUrl: "https://example.com/project",
|
|
80
|
+
|
|
81
|
+
impact: {
|
|
82
|
+
scope: ["Climate Change", "Carbon Capture"],
|
|
83
|
+
work: {
|
|
84
|
+
from: "2024-01-01",
|
|
85
|
+
to: "2025-12-31",
|
|
86
|
+
},
|
|
87
|
+
contributors: ["did:plc:researcher1", "did:plc:researcher2"],
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
rights: {
|
|
91
|
+
license: "CC-BY-4.0",
|
|
92
|
+
allowsDerivatives: true,
|
|
93
|
+
transferrable: false,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
console.log("Created hypercert:", hypercert.uri);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### Retrieving Hypercerts
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// Get a specific hypercert by URI
|
|
104
|
+
const hypercert = await repo.hypercerts.get(
|
|
105
|
+
"at://did:plc:user123/org.hypercerts.claim/abc123"
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// List all hypercerts in the repository
|
|
109
|
+
const { records } = await repo.hypercerts.list();
|
|
110
|
+
for (const claim of records) {
|
|
111
|
+
console.log(claim.value.title);
|
|
112
|
+
}
|
|
71
113
|
|
|
72
|
-
//
|
|
73
|
-
const
|
|
114
|
+
// List with pagination
|
|
115
|
+
const { records, cursor } = await repo.hypercerts.list({ limit: 10 });
|
|
116
|
+
if (cursor) {
|
|
117
|
+
const nextPage = await repo.hypercerts.list({ limit: 10, cursor });
|
|
118
|
+
}
|
|
74
119
|
```
|
|
75
120
|
|
|
76
|
-
|
|
121
|
+
#### Updating a Hypercert
|
|
77
122
|
|
|
123
|
+
```typescript
|
|
124
|
+
// Update an existing hypercert
|
|
125
|
+
await repo.hypercerts.update(
|
|
126
|
+
"at://did:plc:user123/org.hypercerts.claim/abc123",
|
|
127
|
+
{
|
|
128
|
+
title: "Updated Climate Research Project",
|
|
129
|
+
description: "Expanded scope to include renewable energy",
|
|
130
|
+
impact: {
|
|
131
|
+
scope: ["Climate Change", "Carbon Capture", "Renewable Energy"],
|
|
132
|
+
work: { from: "2024-01-01", to: "2026-12-31" },
|
|
133
|
+
contributors: ["did:plc:researcher1", "did:plc:researcher2"],
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
);
|
|
78
137
|
```
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
138
|
+
|
|
139
|
+
#### Deleting a Hypercert
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
await repo.hypercerts.delete(
|
|
143
|
+
"at://did:plc:user123/org.hypercerts.claim/abc123"
|
|
144
|
+
);
|
|
86
145
|
```
|
|
87
146
|
|
|
88
|
-
###
|
|
147
|
+
### 3. Contributions and Measurements
|
|
148
|
+
|
|
149
|
+
#### Adding Contributions
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// Add a contribution to a hypercert
|
|
153
|
+
const contribution = await repo.hypercerts.addContribution({
|
|
154
|
+
claim: "at://did:plc:user123/org.hypercerts.claim/abc123",
|
|
155
|
+
contributor: "did:plc:contributor456",
|
|
156
|
+
description: "Led the research team and conducted field studies",
|
|
157
|
+
contributionType: "Work",
|
|
158
|
+
percentage: 40.0,
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### Adding Measurements
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// Add a measurement/evaluation
|
|
166
|
+
const measurement = await repo.hypercerts.addMeasurement({
|
|
167
|
+
claim: "at://did:plc:user123/org.hypercerts.claim/abc123",
|
|
168
|
+
type: "Impact",
|
|
169
|
+
value: 1000,
|
|
170
|
+
unit: "trees planted",
|
|
171
|
+
verifiedBy: "did:plc:auditor789",
|
|
172
|
+
verificationMethod: "On-site inspection with GPS verification",
|
|
173
|
+
measuredAt: new Date().toISOString(),
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 4. Blob Operations (Images & Files)
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Upload an image or file
|
|
181
|
+
const blobResult = await repo.blobs.upload(imageFile);
|
|
182
|
+
console.log("Blob uploaded:", blobResult.ref.$link);
|
|
183
|
+
|
|
184
|
+
// Download a blob
|
|
185
|
+
const blobData = await repo.blobs.get(
|
|
186
|
+
"did:plc:user123",
|
|
187
|
+
"bafyreiabc123..."
|
|
188
|
+
);
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 5. Organizations (SDS only)
|
|
192
|
+
|
|
193
|
+
Organizations allow multiple users to collaborate on shared repositories.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Create an organization
|
|
197
|
+
const org = await repo.organizations.create({
|
|
198
|
+
name: "Climate Research Institute",
|
|
199
|
+
description: "Leading research on climate solutions",
|
|
200
|
+
handle: "climate-research", // optional: unique handle
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
console.log("Organization DID:", org.did);
|
|
204
|
+
|
|
205
|
+
// List all organizations you belong to
|
|
206
|
+
const { organizations } = await repo.organizations.list();
|
|
207
|
+
for (const org of organizations) {
|
|
208
|
+
console.log(`${org.name} (${org.role})`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// List with pagination
|
|
212
|
+
const { organizations, cursor } = await repo.organizations.list({ limit: 10 });
|
|
213
|
+
|
|
214
|
+
// Get a specific organization
|
|
215
|
+
const org = await repo.organizations.get("did:plc:org123");
|
|
216
|
+
console.log(`${org.name} - ${org.description}`);
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### 6. Collaborator Management (SDS only)
|
|
220
|
+
|
|
221
|
+
Manage who has access to your repository and what they can do.
|
|
222
|
+
|
|
223
|
+
#### Granting Access
|
|
89
224
|
|
|
90
225
|
```typescript
|
|
91
|
-
// Grant
|
|
226
|
+
// Grant different levels of access
|
|
92
227
|
await repo.collaborators.grant({
|
|
93
228
|
userDid: "did:plc:user123",
|
|
94
229
|
role: "editor", // viewer | editor | admin | owner
|
|
95
230
|
});
|
|
96
231
|
|
|
97
|
-
//
|
|
98
|
-
|
|
232
|
+
// Roles explained:
|
|
233
|
+
// - viewer: Read-only access
|
|
234
|
+
// - editor: Can create and edit records
|
|
235
|
+
// - admin: Can manage collaborators and settings
|
|
236
|
+
// - owner: Full control (same as repository owner)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### Managing Collaborators
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// List all collaborators with pagination
|
|
243
|
+
const { collaborators, cursor } = await repo.collaborators.list();
|
|
244
|
+
for (const collab of collaborators) {
|
|
245
|
+
console.log(`${collab.userDid} - ${collab.role}`);
|
|
246
|
+
}
|
|
99
247
|
|
|
100
|
-
// List
|
|
101
|
-
|
|
248
|
+
// List next page
|
|
249
|
+
if (cursor) {
|
|
250
|
+
const nextPage = await repo.collaborators.list({ cursor, limit: 20 });
|
|
251
|
+
}
|
|
102
252
|
|
|
103
|
-
// Check if user has access
|
|
253
|
+
// Check if a user has access
|
|
104
254
|
const hasAccess = await repo.collaborators.hasAccess("did:plc:user123");
|
|
105
255
|
|
|
106
|
-
// Get user's role
|
|
256
|
+
// Get a specific user's role
|
|
107
257
|
const role = await repo.collaborators.getRole("did:plc:user123");
|
|
258
|
+
console.log(`User role: ${role}`); // "editor", "admin", etc.
|
|
108
259
|
|
|
109
260
|
// Get current user's permissions
|
|
110
261
|
const permissions = await repo.collaborators.getPermissions();
|
|
111
262
|
if (permissions.admin) {
|
|
112
|
-
|
|
263
|
+
console.log("You can manage collaborators");
|
|
113
264
|
}
|
|
265
|
+
if (permissions.create) {
|
|
266
|
+
console.log("You can create records");
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### Revoking Access
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// Remove a collaborator
|
|
274
|
+
await repo.collaborators.revoke({
|
|
275
|
+
userDid: "did:plc:user123",
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### Transferring Ownership
|
|
114
280
|
|
|
115
|
-
|
|
281
|
+
```typescript
|
|
282
|
+
// Transfer repository ownership (irreversible!)
|
|
116
283
|
await repo.collaborators.transferOwnership({
|
|
117
|
-
newOwnerDid: "did:plc:
|
|
284
|
+
newOwnerDid: "did:plc:newowner456",
|
|
118
285
|
});
|
|
119
286
|
```
|
|
120
287
|
|
|
121
|
-
###
|
|
288
|
+
### 7. Generic Record Operations
|
|
289
|
+
|
|
290
|
+
For working with any ATProto record type:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
// Create a generic record
|
|
294
|
+
const record = await repo.records.create({
|
|
295
|
+
collection: "org.hypercerts.claim",
|
|
296
|
+
record: {
|
|
297
|
+
$type: "org.hypercerts.claim",
|
|
298
|
+
title: "My Claim",
|
|
299
|
+
// ... record data
|
|
300
|
+
},
|
|
301
|
+
});
|
|
122
302
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
| Organizations | ❌ | ✅ | `com.sds.organization.*` |
|
|
129
|
-
| Collaborators | ❌ | ✅ | `com.sds.repo.*` |
|
|
303
|
+
// Get a record
|
|
304
|
+
const record = await repo.records.get({
|
|
305
|
+
collection: "org.hypercerts.claim",
|
|
306
|
+
rkey: "abc123",
|
|
307
|
+
});
|
|
130
308
|
|
|
131
|
-
|
|
309
|
+
// Update a record
|
|
310
|
+
await repo.records.update({
|
|
311
|
+
collection: "org.hypercerts.claim",
|
|
312
|
+
rkey: "abc123",
|
|
313
|
+
record: {
|
|
314
|
+
$type: "org.hypercerts.claim",
|
|
315
|
+
title: "Updated Title",
|
|
316
|
+
// ... updated data
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Delete a record
|
|
321
|
+
await repo.records.delete({
|
|
322
|
+
collection: "org.hypercerts.claim",
|
|
323
|
+
rkey: "abc123",
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// List records with pagination
|
|
327
|
+
const { records, cursor } = await repo.records.list({
|
|
328
|
+
collection: "org.hypercerts.claim",
|
|
329
|
+
limit: 50,
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### 8. Profile Management (PDS only)
|
|
132
334
|
|
|
133
335
|
```typescript
|
|
134
|
-
|
|
336
|
+
// Get user profile
|
|
337
|
+
const profile = await repo.profile.get();
|
|
338
|
+
console.log(`${profile.displayName} (@${profile.handle})`);
|
|
339
|
+
|
|
340
|
+
// Update profile
|
|
341
|
+
await repo.profile.update({
|
|
342
|
+
displayName: "Jane Researcher",
|
|
343
|
+
description: "Climate scientist and hypercert enthusiast",
|
|
344
|
+
avatar: avatarBlob, // optional
|
|
345
|
+
banner: bannerBlob, // optional
|
|
346
|
+
});
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## API Reference
|
|
350
|
+
|
|
351
|
+
### Repository Operations
|
|
352
|
+
|
|
353
|
+
| Operation | Method | PDS | SDS | Returns |
|
|
354
|
+
|-----------|--------|-----|-----|---------|
|
|
355
|
+
| **Records** | | | | |
|
|
356
|
+
| Create record | `repo.records.create()` | ✅ | ✅ | `{ uri, cid }` |
|
|
357
|
+
| Get record | `repo.records.get()` | ✅ | ✅ | Record data |
|
|
358
|
+
| Update record | `repo.records.update()` | ✅ | ✅ | `{ uri, cid }` |
|
|
359
|
+
| Delete record | `repo.records.delete()` | ✅ | ✅ | void |
|
|
360
|
+
| List records | `repo.records.list()` | ✅ | ✅ | `{ records, cursor? }` |
|
|
361
|
+
| **Hypercerts** | | | | |
|
|
362
|
+
| Create hypercert | `repo.hypercerts.create()` | ✅ | ✅ | `{ uri, cid, value }` |
|
|
363
|
+
| Get hypercert | `repo.hypercerts.get()` | ✅ | ✅ | Full hypercert |
|
|
364
|
+
| Update hypercert | `repo.hypercerts.update()` | ✅ | ✅ | `{ uri, cid }` |
|
|
365
|
+
| Delete hypercert | `repo.hypercerts.delete()` | ✅ | ✅ | void |
|
|
366
|
+
| List hypercerts | `repo.hypercerts.list()` | ✅ | ✅ | `{ records, cursor? }` |
|
|
367
|
+
| Add contribution | `repo.hypercerts.addContribution()` | ✅ | ✅ | Contribution |
|
|
368
|
+
| Add measurement | `repo.hypercerts.addMeasurement()` | ✅ | ✅ | Measurement |
|
|
369
|
+
| **Blobs** | | | | |
|
|
370
|
+
| Upload blob | `repo.blobs.upload()` | ✅ | ✅ | `{ ref, mimeType, size }` |
|
|
371
|
+
| Get blob | `repo.blobs.get()` | ✅ | ✅ | Blob data |
|
|
372
|
+
| **Profile** | | | | |
|
|
373
|
+
| Get profile | `repo.profile.get()` | ✅ | ❌ | Profile data |
|
|
374
|
+
| Update profile | `repo.profile.update()` | ✅ | ❌ | void |
|
|
375
|
+
| **Organizations** | | | | |
|
|
376
|
+
| Create org | `repo.organizations.create()` | ❌ | ✅ | `{ did, name, ... }` |
|
|
377
|
+
| Get org | `repo.organizations.get()` | ❌ | ✅ | Organization |
|
|
378
|
+
| List orgs | `repo.organizations.list()` | ❌ | ✅ | `{ organizations, cursor? }` |
|
|
379
|
+
| **Collaborators** | | | | |
|
|
380
|
+
| Grant access | `repo.collaborators.grant()` | ❌ | ✅ | void |
|
|
381
|
+
| Revoke access | `repo.collaborators.revoke()` | ❌ | ✅ | void |
|
|
382
|
+
| List collaborators | `repo.collaborators.list()` | ❌ | ✅ | `{ collaborators, cursor? }` |
|
|
383
|
+
| Check access | `repo.collaborators.hasAccess()` | ❌ | ✅ | boolean |
|
|
384
|
+
| Get role | `repo.collaborators.getRole()` | ❌ | ✅ | Role string |
|
|
385
|
+
| Get permissions | `repo.collaborators.getPermissions()` | ❌ | ✅ | Permissions |
|
|
386
|
+
| Transfer ownership | `repo.collaborators.transferOwnership()` | ❌ | ✅ | void |
|
|
387
|
+
|
|
388
|
+
## Type System
|
|
389
|
+
|
|
390
|
+
Types are generated from ATProto lexicon definitions and exported with friendly aliases:
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
import type {
|
|
394
|
+
HypercertClaim,
|
|
395
|
+
HypercertRights,
|
|
396
|
+
HypercertContribution,
|
|
397
|
+
HypercertMeasurement,
|
|
398
|
+
HypercertEvaluation,
|
|
399
|
+
HypercertCollection,
|
|
400
|
+
HypercertLocation,
|
|
401
|
+
} from "@hypercerts-org/sdk-core";
|
|
402
|
+
|
|
403
|
+
// For validation, use namespaced imports
|
|
404
|
+
import { OrgHypercertsClaim } from "@hypercerts-org/sdk-core";
|
|
405
|
+
|
|
406
|
+
if (OrgHypercertsClaim.isRecord(data)) {
|
|
407
|
+
// data is typed as HypercertClaim
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
| Lexicon Type | SDK Alias |
|
|
412
|
+
|--------------|-----------|
|
|
413
|
+
| `OrgHypercertsClaim.Main` | `HypercertClaim` |
|
|
414
|
+
| `OrgHypercertsClaimRights.Main` | `HypercertRights` |
|
|
415
|
+
| `OrgHypercertsClaimContribution.Main` | `HypercertContribution` |
|
|
416
|
+
| `OrgHypercertsClaimMeasurement.Main` | `HypercertMeasurement` |
|
|
417
|
+
| `OrgHypercertsClaimEvaluation.Main` | `HypercertEvaluation` |
|
|
418
|
+
| `OrgHypercertsCollection.Main` | `HypercertCollection` |
|
|
419
|
+
| `AppCertifiedLocation.Main` | `HypercertLocation` |
|
|
420
|
+
|
|
421
|
+
## Error Handling
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
import {
|
|
425
|
+
ValidationError,
|
|
426
|
+
NetworkError,
|
|
427
|
+
AuthenticationError,
|
|
428
|
+
SDSRequiredError,
|
|
429
|
+
} from "@hypercerts-org/sdk-core/errors";
|
|
430
|
+
|
|
431
|
+
try {
|
|
432
|
+
await repo.hypercerts.create({ ... });
|
|
433
|
+
} catch (error) {
|
|
434
|
+
if (error instanceof ValidationError) {
|
|
435
|
+
console.error("Invalid hypercert data:", error.message);
|
|
436
|
+
} else if (error instanceof NetworkError) {
|
|
437
|
+
console.error("Network issue:", error.message);
|
|
438
|
+
} else if (error instanceof AuthenticationError) {
|
|
439
|
+
console.error("Authentication failed:", error.message);
|
|
440
|
+
} else if (error instanceof SDSRequiredError) {
|
|
441
|
+
console.error("This operation requires SDS:", error.message);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## Package Entrypoints
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
@hypercerts-org/sdk-core
|
|
450
|
+
├── / → Full SDK (createATProtoSDK, Repository, types, errors)
|
|
451
|
+
├── /types → TypeScript types (re-exported from @hypercerts-org/lexicon)
|
|
452
|
+
├── /errors → Error classes
|
|
453
|
+
├── /lexicons → LexiconRegistry, HYPERCERT_LEXICONS, HYPERCERT_COLLECTIONS
|
|
454
|
+
├── /storage → InMemorySessionStore, InMemoryStateStore
|
|
455
|
+
└── /testing → createMockSession, MockSessionStore
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
## Advanced Usage
|
|
459
|
+
|
|
460
|
+
### Custom Session Storage
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
import { createATProtoSDK } from "@hypercerts-org/sdk-core";
|
|
464
|
+
import { InMemorySessionStore } from "@hypercerts-org/sdk-core/storage";
|
|
465
|
+
|
|
466
|
+
const sdk = createATProtoSDK({
|
|
467
|
+
oauth: { ... },
|
|
468
|
+
sessionStore: new InMemorySessionStore(),
|
|
469
|
+
});
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Testing with Mocks
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
import { createMockSession, MockSessionStore } from "@hypercerts-org/sdk-core/testing";
|
|
476
|
+
|
|
477
|
+
const mockSession = createMockSession({
|
|
478
|
+
did: "did:plc:test123",
|
|
479
|
+
handle: "test.user",
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
const mockStore = new MockSessionStore();
|
|
483
|
+
await mockStore.set(mockSession);
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Working with Lexicons
|
|
487
|
+
|
|
488
|
+
```typescript
|
|
489
|
+
import {
|
|
490
|
+
LexiconRegistry,
|
|
491
|
+
HYPERCERT_LEXICONS,
|
|
492
|
+
HYPERCERT_COLLECTIONS,
|
|
493
|
+
} from "@hypercerts-org/sdk-core/lexicons";
|
|
494
|
+
|
|
495
|
+
const registry = new LexiconRegistry();
|
|
496
|
+
registry.registerLexicons(HYPERCERT_LEXICONS);
|
|
497
|
+
|
|
498
|
+
// Validate a record
|
|
499
|
+
const isValid = registry.validate(
|
|
500
|
+
"org.hypercerts.claim",
|
|
501
|
+
claimData
|
|
502
|
+
);
|
|
135
503
|
```
|
|
136
504
|
|
|
137
505
|
## Development
|
|
138
506
|
|
|
139
507
|
```bash
|
|
140
|
-
pnpm
|
|
141
|
-
pnpm
|
|
142
|
-
pnpm test
|
|
508
|
+
pnpm install # Install dependencies
|
|
509
|
+
pnpm build # Build the package
|
|
510
|
+
pnpm test # Run tests
|
|
511
|
+
pnpm test:coverage # Run tests with coverage
|
|
512
|
+
pnpm test:watch # Run tests in watch mode
|
|
143
513
|
```
|
|
514
|
+
|
|
515
|
+
## License
|
|
516
|
+
|
|
517
|
+
MIT
|
|
518
|
+
|
|
519
|
+
## Resources
|
|
520
|
+
|
|
521
|
+
- [ATProto Documentation](https://atproto.com/docs)
|
|
522
|
+
- [Hypercerts Documentation](https://hypercerts.org)
|
|
523
|
+
- [GitHub Repository](https://github.com/hypercerts-org/hypercerts-sdk)
|