@hypercerts-org/sdk-core 0.10.0-beta.4 → 0.10.0-beta.6
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 +226 -0
- package/README.md +309 -45
- package/dist/index.cjs +2749 -347
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1961 -182
- package/dist/index.mjs +3769 -1397
- package/dist/index.mjs.map +1 -1
- package/dist/lexicons.cjs +446 -34
- package/dist/lexicons.cjs.map +1 -1
- package/dist/lexicons.d.ts +248 -8
- package/dist/lexicons.mjs +422 -11
- package/dist/lexicons.mjs.map +1 -1
- package/dist/testing.d.ts +56 -9
- package/dist/types.cjs +89 -9
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.ts +438 -97
- package/dist/types.mjs +89 -9
- package/dist/types.mjs.map +1 -1
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,231 @@
|
|
|
1
1
|
# @hypercerts-org/sdk-core
|
|
2
2
|
|
|
3
|
+
## 0.10.0-beta.6
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#101](https://github.com/hypercerts-org/hypercerts-sdk/pull/101)
|
|
8
|
+
[`bf93b3c`](https://github.com/hypercerts-org/hypercerts-sdk/commit/bf93b3cf5d5eccb12de31c4fe6f95ed3676c746e) Thanks
|
|
9
|
+
[@aspiers](https://github.com/aspiers)! - feat: align collection/project types with lexicon + add inline location
|
|
10
|
+
support
|
|
11
|
+
|
|
12
|
+
This is a BREAKING change.
|
|
13
|
+
|
|
14
|
+
**Type Alignment with Lexicon:**
|
|
15
|
+
- Changed `createCollection` to use lexicon-aligned `items` array instead of `claims`
|
|
16
|
+
- Updated avatar/banner handling to use proper lexicon union types
|
|
17
|
+
- Simplified project methods to delegate to collection methods
|
|
18
|
+
- Added `CreateCollectionParams`, `UpdateCollectionParams`, and result types derived from lexicon
|
|
19
|
+
- Improved type safety by deriving SDK input types from lexicon definitions
|
|
20
|
+
|
|
21
|
+
**Inline Location Support:**
|
|
22
|
+
|
|
23
|
+
`AttachLocationParams` now supports three ways to specify location:
|
|
24
|
+
1. **StrongRef** - Direct reference with uri and cid (no record creation)
|
|
25
|
+
2. **AT-URI string** - Reference to existing location record
|
|
26
|
+
3. **Location object** - Full location data to create a new location record
|
|
27
|
+
|
|
28
|
+
**Changes:**
|
|
29
|
+
- Add `AttachLocationParams` union type supporting StrongRef, string URI, or location object
|
|
30
|
+
- Add optional `location` field to `CreateCollectionParams`
|
|
31
|
+
- Add optional `location` field to `UpdateCollectionParams` (supports `null` to remove)
|
|
32
|
+
- Update `CreateCollectionResult` to include optional `locationUri` field
|
|
33
|
+
- Implement location handling in `createCollection()` - supports all three forms
|
|
34
|
+
- Add tests for collection creation with StrongRef, string URI, and location object
|
|
35
|
+
|
|
36
|
+
**Example Usage:**
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Create a project with location (StrongRef - direct reference)
|
|
40
|
+
const project = await repo.hypercerts.createProject({
|
|
41
|
+
title: "Climate Initiative",
|
|
42
|
+
items: [...],
|
|
43
|
+
location: { uri: "at://did:plc:alice/app.certified.location/abc", cid: "bafy..." },
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Create with location (AT-URI string - fetches CID)
|
|
47
|
+
const project2 = await repo.hypercerts.createProject({
|
|
48
|
+
title: "Forest Project",
|
|
49
|
+
items: [...],
|
|
50
|
+
location: "at://did:plc:bob/app.certified.location/xyz",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Create with location (location object - creates new record)
|
|
54
|
+
const project3 = await repo.hypercerts.createProject({
|
|
55
|
+
title: "Ocean Project",
|
|
56
|
+
items: [...],
|
|
57
|
+
location: {
|
|
58
|
+
lpVersion: "1.0",
|
|
59
|
+
srs: "EPSG:4326",
|
|
60
|
+
locationType: "coordinate-decimal",
|
|
61
|
+
location: "37.7749, -122.4194",
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Update project to change location
|
|
66
|
+
await repo.hypercerts.updateProject(project.uri, {
|
|
67
|
+
location: "at://did:plc:alice/app.certified.location/new",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Remove location
|
|
71
|
+
await repo.hypercerts.updateProject(project.uri, {
|
|
72
|
+
location: null,
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 0.10.0-beta.5
|
|
77
|
+
|
|
78
|
+
### Minor Changes
|
|
79
|
+
|
|
80
|
+
- [#87](https://github.com/hypercerts-org/hypercerts-sdk/pull/87)
|
|
81
|
+
[`85b1350`](https://github.com/hypercerts-org/hypercerts-sdk/commit/85b13502791e49966dae3d0dd0e833905c59abe3) Thanks
|
|
82
|
+
[@bitbeckers](https://github.com/bitbeckers)! - Add comprehensive project support to SDK
|
|
83
|
+
|
|
84
|
+
**Core SDK (`@hypercerts-org/sdk-core`):**
|
|
85
|
+
- Add project CRUD operations (createProject, getProject, listProjects, updateProject, deleteProject)
|
|
86
|
+
- Add project events (projectCreated, projectUpdated, projectDeleted)
|
|
87
|
+
- Support for avatar and coverPhoto blob uploads
|
|
88
|
+
- Activities array with weight values
|
|
89
|
+
- Location reference support
|
|
90
|
+
- 34 comprehensive tests with full coverage
|
|
91
|
+
|
|
92
|
+
**React SDK (`@hypercerts-org/sdk-react`):**
|
|
93
|
+
- Add useProjects and useProject hooks
|
|
94
|
+
- Project query keys for cache management
|
|
95
|
+
- TypeScript types for projects (Project, CreateProjectParams, UpdateProjectParams)
|
|
96
|
+
- Test factory support for project hooks
|
|
97
|
+
- Full pagination and optimistic updates support
|
|
98
|
+
|
|
99
|
+
Projects organize multiple hypercert activities with metadata including title, shortDescription, description (Leaflet
|
|
100
|
+
documents), avatar, cover photo, activities with weights, and location references.
|
|
101
|
+
|
|
102
|
+
- [#98](https://github.com/hypercerts-org/hypercerts-sdk/pull/98)
|
|
103
|
+
[`f9dd27f`](https://github.com/hypercerts-org/hypercerts-sdk/commit/f9dd27f78de0ee49aab9079e76566f272b161cd0) Thanks
|
|
104
|
+
[@bitbeckers](https://github.com/bitbeckers)! - Add BaseOperations abstract class for building custom lexicon
|
|
105
|
+
operations. Developers can now extend BaseOperations to create type-safe, validated operation classes for their custom
|
|
106
|
+
lexicons, with built-in helpers for record creation, validation, and strongRef management.
|
|
107
|
+
|
|
108
|
+
- [#98](https://github.com/hypercerts-org/hypercerts-sdk/pull/98)
|
|
109
|
+
[`e850310`](https://github.com/hypercerts-org/hypercerts-sdk/commit/e850310d26e0561bdcfb778a6ef3bedbb7453eed) Thanks
|
|
110
|
+
[@bitbeckers](https://github.com/bitbeckers)! - Add comprehensive documentation and examples for custom lexicons.
|
|
111
|
+
Includes custom-lexicons.md guide, sidecar-pattern.md guide, and a complete working example with tests demonstrating
|
|
112
|
+
how to create and use custom lexicons for evaluating hypercerts.
|
|
113
|
+
|
|
114
|
+
- [#84](https://github.com/hypercerts-org/hypercerts-sdk/pull/84)
|
|
115
|
+
[`3157c18`](https://github.com/hypercerts-org/hypercerts-sdk/commit/3157c188c70e2f9473ee14eddaf635e3fbd346a1) Thanks
|
|
116
|
+
[@Kzoeps](https://github.com/Kzoeps)! - Evidence records are now created separately instead of being embedded inline
|
|
117
|
+
in hypercerts
|
|
118
|
+
- `create()` now calls `addEvidence()` for each evidence item using `Promise.all()` for parallel creation
|
|
119
|
+
- Remove inline evidence embedding from hypercert records
|
|
120
|
+
- Add `evidenceUris?: string[]` to `CreateHypercertResult` interface
|
|
121
|
+
- Add `createEvidenceWithProgress()` helper method with "addEvidence" progress tracking
|
|
122
|
+
- `addEvidence()` SDK constructs `$type`, `createdAt`, and `subject` fields internally
|
|
123
|
+
|
|
124
|
+
**Breaking Changes:**
|
|
125
|
+
- Evidence is no longer embedded in the hypercert record - use `result.evidenceUris` to access evidence record URIs
|
|
126
|
+
- `addEvidence()` now accepts a single `CreateHypercertEvidenceParams` object instead of
|
|
127
|
+
`(uri: string, evidence: HypercertEvidence[])`
|
|
128
|
+
|
|
129
|
+
- [#98](https://github.com/hypercerts-org/hypercerts-sdk/pull/98)
|
|
130
|
+
[`0cd3b26`](https://github.com/hypercerts-org/hypercerts-sdk/commit/0cd3b26eb779246e9ef094f614f2f77807926f1b) Thanks
|
|
131
|
+
[@bitbeckers](https://github.com/bitbeckers)! - Add LexiconRegistry for custom lexicon management. Developers can now
|
|
132
|
+
register custom lexicon schemas at runtime and validate records against registered schemas before creation. The
|
|
133
|
+
registry supports:
|
|
134
|
+
- Registering custom lexicon definitions from JSON
|
|
135
|
+
- Validating records against registered schemas
|
|
136
|
+
- Querying registered lexicons
|
|
137
|
+
- Managing lexicon lifecycle (register/unregister)
|
|
138
|
+
|
|
139
|
+
This enables developers to extend the SDK with custom record types that can reference hypercerts and other records
|
|
140
|
+
using strongRefs.
|
|
141
|
+
|
|
142
|
+
- [#98](https://github.com/hypercerts-org/hypercerts-sdk/pull/98)
|
|
143
|
+
[`b87cb22`](https://github.com/hypercerts-org/hypercerts-sdk/commit/b87cb2265d924b531eef8d58c669dc931b61e561) Thanks
|
|
144
|
+
[@bitbeckers](https://github.com/bitbeckers)! - Add lexicon development utilities for custom lexicons. Developers can
|
|
145
|
+
now use helper functions for AT-URI parsing, strongRef creation, lexicon schema building, and sidecar pattern
|
|
146
|
+
implementation. This includes:
|
|
147
|
+
- AT-URI utilities: parseAtUri, buildAtUri, extractRkeyFromUri, isValidAtUri
|
|
148
|
+
- StrongRef utilities: createStrongRef, createStrongRefFromResult, validateStrongRef
|
|
149
|
+
- Lexicon builders: createStringField, createIntegerField, createStrongRefField, createRecordDef, createLexiconDoc,
|
|
150
|
+
and more
|
|
151
|
+
- Sidecar pattern: createSidecarRecord, attachSidecar, createWithSidecars, batchCreateSidecars
|
|
152
|
+
|
|
153
|
+
- [#88](https://github.com/hypercerts-org/hypercerts-sdk/pull/88)
|
|
154
|
+
[`19c78df`](https://github.com/hypercerts-org/hypercerts-sdk/commit/19c78dfef448fb43d353d95721c13f3a35618fb3) Thanks
|
|
155
|
+
[@bitbeckers](https://github.com/bitbeckers)! - feat: add HTTP loopback URL support for local development
|
|
156
|
+
|
|
157
|
+
Enable local development and testing with HTTP loopback URLs (`http://localhost`, `http://127.0.0.1`, `http://[::1]`)
|
|
158
|
+
while maintaining security for production deployments.
|
|
159
|
+
|
|
160
|
+
**Configuration Updates**
|
|
161
|
+
- Custom URL validator accepting HTTPS URLs or HTTP loopback addresses
|
|
162
|
+
- Update `OAuthConfigSchema` to allow loopback URLs for `clientId`, `redirectUri`, `jwksUri`
|
|
163
|
+
- Add optional `developmentMode` boolean flag to suppress warnings
|
|
164
|
+
- Update `ServerConfigSchema` to allow loopback URLs for PDS/SDS servers
|
|
165
|
+
- Export `isLoopbackUrl()` helper function and TypeScript types (`LoopbackUrl`, `HttpsUrl`,
|
|
166
|
+
`DevelopmentOrProductionUrl`)
|
|
167
|
+
|
|
168
|
+
**Development Mode Features**
|
|
169
|
+
- Automatic loopback detection with informative logging
|
|
170
|
+
- Warning when using loopback URLs without explicit `developmentMode` flag
|
|
171
|
+
- Info logs indicating development mode is active
|
|
172
|
+
- Clear guidance about authorization server requirements
|
|
173
|
+
|
|
174
|
+
**Testing**
|
|
175
|
+
- 28 new unit tests for loopback URL validation
|
|
176
|
+
- Tests cover localhost, 127.0.0.1, and [::1] (IPv6) loopback addresses
|
|
177
|
+
- Tests verify rejection of non-loopback HTTP URLs
|
|
178
|
+
- Tests ensure HTTPS URLs always accepted
|
|
179
|
+
|
|
180
|
+
**Documentation**
|
|
181
|
+
- Comprehensive local development guide in Core SDK README
|
|
182
|
+
- NextJS App Router example with loopback configuration
|
|
183
|
+
- API route setup examples (OAuth callback, JWKS endpoint)
|
|
184
|
+
- Important notes about authorization server support and production safety
|
|
185
|
+
- Local development example added to React SDK factory JSDoc
|
|
186
|
+
|
|
187
|
+
**Breaking Changes**: None - fully backward compatible
|
|
188
|
+
|
|
189
|
+
**Migration**: No migration needed for existing configurations. Existing HTTPS URLs continue to work without changes.
|
|
190
|
+
|
|
191
|
+
This feature enables developers to test the SDK locally without requiring HTTPS certificates, while the underlying
|
|
192
|
+
`@atproto/oauth-client-node` library handles loopback OAuth flows per the AT Protocol specification.
|
|
193
|
+
|
|
194
|
+
- [#98](https://github.com/hypercerts-org/hypercerts-sdk/pull/98)
|
|
195
|
+
[`3554580`](https://github.com/hypercerts-org/hypercerts-sdk/commit/3554580d77d9467c88c779e75a96a08d3e17bfd7) Thanks
|
|
196
|
+
[@bitbeckers](https://github.com/bitbeckers)! - Add automatic lexicon validation to RecordOperations. Records are now
|
|
197
|
+
validated against registered lexicon schemas before being sent to the server, catching schema violations early.
|
|
198
|
+
Validation can be bypassed using the `skipValidation` parameter for advanced use cases.
|
|
199
|
+
|
|
200
|
+
- [#96](https://github.com/hypercerts-org/hypercerts-sdk/pull/96)
|
|
201
|
+
[`eea06a7`](https://github.com/hypercerts-org/hypercerts-sdk/commit/eea06a7f5e4f655ccac635fa8842ea32a6dfde64) Thanks
|
|
202
|
+
[@Kzoeps](https://github.com/Kzoeps)! - Refactor location attachment to match lexicon specifications
|
|
203
|
+
|
|
204
|
+
**New Features:**
|
|
205
|
+
- Add `AttachLocationParams` interface exported from SDK for type-safe location attachment
|
|
206
|
+
- Location data now properly uses `org.hypercerts.defs#uri` (for string URIs) or `org.hypercerts.defs#smallBlob` (for
|
|
207
|
+
GeoJSON blobs) to match lexicon spec
|
|
208
|
+
- Add `lpVersion` and `locationType` fields to location parameters for better protocol compliance
|
|
209
|
+
|
|
210
|
+
**Improvements:**
|
|
211
|
+
- Centralized blob upload logic with new `handleBlobUpload()` helper method
|
|
212
|
+
- Simplified location type detection - now based on content type (string vs Blob) instead of separate `geojson`
|
|
213
|
+
parameter
|
|
214
|
+
- Improved type safety with structured `AttachLocationParams` interface
|
|
215
|
+
|
|
216
|
+
**Breaking Changes:**
|
|
217
|
+
- `attachLocation()` signature changed from `(uri, { value, name?, description?, srs, geojson? })` to
|
|
218
|
+
`(uri, AttachLocationParams)`
|
|
219
|
+
- `AttachLocationParams` now requires: `lpVersion`, `srs`, `locationType`, and `location` (string | Blob)
|
|
220
|
+
- The `location` field in `CreateHypercertParams` now uses `AttachLocationParams` type instead of inline object
|
|
221
|
+
- Removed separate `value` and `geojson` fields - use single `location` field with either string or Blob
|
|
222
|
+
|
|
223
|
+
- [#98](https://github.com/hypercerts-org/hypercerts-sdk/pull/98)
|
|
224
|
+
[`e0ef6e9`](https://github.com/hypercerts-org/hypercerts-sdk/commit/e0ef6e9cb9138590e81b4a2929ca27ae557d2f39) Thanks
|
|
225
|
+
[@bitbeckers](https://github.com/bitbeckers)! - Integrate LexiconRegistry into SDK and Repository. The SDK now
|
|
226
|
+
initializes a LexiconRegistry with hypercert lexicons by default and exposes it via `getLexiconRegistry()`. Repository
|
|
227
|
+
instances receive the registry and pass it to RecordOperations for future validation support.
|
|
228
|
+
|
|
3
229
|
## 0.10.0-beta.4
|
|
4
230
|
|
|
5
231
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -51,6 +51,99 @@ const claim = await repo.hypercerts.create({
|
|
|
51
51
|
});
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
## Local Development
|
|
55
|
+
|
|
56
|
+
For local development and testing, you can use HTTP loopback URLs with `localhost` or `127.0.0.1`:
|
|
57
|
+
|
|
58
|
+
### NextJS App Router Example
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// lib/atproto.ts
|
|
62
|
+
import { createATProtoSDK } from "@hypercerts-org/sdk-core";
|
|
63
|
+
|
|
64
|
+
const sdk = createATProtoSDK({
|
|
65
|
+
oauth: {
|
|
66
|
+
// Use localhost for client_id (loopback client)
|
|
67
|
+
clientId: "http://localhost/",
|
|
68
|
+
|
|
69
|
+
// Use 127.0.0.1 with your app's port for redirect
|
|
70
|
+
redirectUri: "http://127.0.0.1:3000/api/auth/callback",
|
|
71
|
+
|
|
72
|
+
scope: "atproto",
|
|
73
|
+
|
|
74
|
+
// Serve JWKS from your app
|
|
75
|
+
jwksUri: "http://127.0.0.1:3000/.well-known/jwks.json",
|
|
76
|
+
|
|
77
|
+
// Load from environment variable
|
|
78
|
+
jwkPrivate: process.env.ATPROTO_JWK_PRIVATE!,
|
|
79
|
+
|
|
80
|
+
// Optional: suppress warnings
|
|
81
|
+
developmentMode: true,
|
|
82
|
+
},
|
|
83
|
+
servers: {
|
|
84
|
+
// Point to local PDS for testing
|
|
85
|
+
pds: "http://localhost:2583",
|
|
86
|
+
},
|
|
87
|
+
logger: console, // Enable debug logging
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export default sdk;
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### API Route Setup
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// app/api/auth/callback/route.ts
|
|
97
|
+
import sdk from "@/lib/atproto";
|
|
98
|
+
|
|
99
|
+
export async function GET(request: Request) {
|
|
100
|
+
const { searchParams } = new URL(request.url);
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const session = await sdk.callback(searchParams);
|
|
104
|
+
|
|
105
|
+
// Store session (use secure httpOnly cookie in production)
|
|
106
|
+
return Response.json({ success: true, did: session.sub });
|
|
107
|
+
} catch (error) {
|
|
108
|
+
return Response.json({ error: "Authentication failed" }, { status: 401 });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Serve JWKS Endpoint
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// app/.well-known/jwks.json/route.ts
|
|
117
|
+
export async function GET() {
|
|
118
|
+
const jwk = JSON.parse(process.env.ATPROTO_JWK_PRIVATE!);
|
|
119
|
+
|
|
120
|
+
// Return public keys only (remove private key 'd' parameter)
|
|
121
|
+
const publicKeys = jwk.keys.map(({ d, ...publicKey }) => publicKey);
|
|
122
|
+
|
|
123
|
+
return Response.json({ keys: publicKeys });
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Environment Variables
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# .env.local
|
|
131
|
+
ATPROTO_JWK_PRIVATE='{"keys":[{"kty":"EC","crv":"P-256",...}]}'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Important Notes
|
|
135
|
+
|
|
136
|
+
> **Authorization Server Support**: The AT Protocol OAuth spec makes loopback support **optional**. Most AT Protocol
|
|
137
|
+
> servers support loopback clients for development, but verify your target authorization server supports this feature.
|
|
138
|
+
|
|
139
|
+
> **Port Matching**: Redirect URIs can use any port - the authorization server ignores port numbers when validating
|
|
140
|
+
> loopback redirects (only the path must match).
|
|
141
|
+
|
|
142
|
+
> **Production Use**: ⚠️ Never use HTTP loopback URLs in production. Always use HTTPS with proper TLS certificates.
|
|
143
|
+
|
|
144
|
+
> **IP vs Hostname**: Use `http://localhost/` for `clientId` and `http://127.0.0.1:<port>` for `redirectUri` and
|
|
145
|
+
> `jwksUri` (this is the recommended pattern per AT Protocol spec).
|
|
146
|
+
|
|
54
147
|
## Core Concepts
|
|
55
148
|
|
|
56
149
|
### 1. PDS vs SDS: Understanding Server Types
|
|
@@ -318,7 +411,130 @@ const measurement = await repo.hypercerts.addMeasurement({
|
|
|
318
411
|
});
|
|
319
412
|
```
|
|
320
413
|
|
|
321
|
-
### 5.
|
|
414
|
+
### 5. Collections and Projects
|
|
415
|
+
|
|
416
|
+
Collections organize multiple hypercerts into logical groupings. Projects are a special type of collection with
|
|
417
|
+
`type="project"`.
|
|
418
|
+
|
|
419
|
+
#### Creating a Collection
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
// Create a collection with weighted items
|
|
423
|
+
const collection = await repo.hypercerts.createCollection({
|
|
424
|
+
title: "Climate Projects 2024",
|
|
425
|
+
shortDescription: "Our climate impact portfolio",
|
|
426
|
+
description: "A curated collection of climate-related hypercerts",
|
|
427
|
+
items: [
|
|
428
|
+
{
|
|
429
|
+
itemIdentifier: { uri: hypercert1Uri, cid: hypercert1Cid },
|
|
430
|
+
itemWeight: "0.5",
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
itemIdentifier: { uri: hypercert2Uri, cid: hypercert2Cid },
|
|
434
|
+
itemWeight: "0.3",
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
itemIdentifier: { uri: hypercert3Uri, cid: hypercert3Cid },
|
|
438
|
+
itemWeight: "0.2",
|
|
439
|
+
},
|
|
440
|
+
],
|
|
441
|
+
avatar: avatarBlob, // optional
|
|
442
|
+
banner: bannerBlob, // optional
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
console.log("Created collection:", collection.uri);
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
#### Creating a Project
|
|
449
|
+
|
|
450
|
+
Projects are collections with automatic `type="project"`:
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
const project = await repo.hypercerts.createProject({
|
|
454
|
+
title: "Rainforest Restoration",
|
|
455
|
+
shortDescription: "Multi-year restoration initiative",
|
|
456
|
+
description: "Comprehensive rainforest restoration project",
|
|
457
|
+
items: [
|
|
458
|
+
{
|
|
459
|
+
itemIdentifier: { uri: activity1Uri, cid: activity1Cid },
|
|
460
|
+
itemWeight: "0.6",
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
itemIdentifier: { uri: activity2Uri, cid: activity2Cid },
|
|
464
|
+
itemWeight: "0.4",
|
|
465
|
+
},
|
|
466
|
+
],
|
|
467
|
+
});
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
#### Attaching Locations
|
|
471
|
+
|
|
472
|
+
Both collections and projects can have location data attached as a sidecar record:
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
// Attach location to a project
|
|
476
|
+
const locationResult = await repo.hypercerts.attachLocationToProject(projectUri, {
|
|
477
|
+
lpVersion: "1.0",
|
|
478
|
+
srs: "EPSG:4326",
|
|
479
|
+
locationType: "coordinate-decimal",
|
|
480
|
+
location: "https://example.com/location.geojson", // or use a Blob
|
|
481
|
+
name: "Project Site",
|
|
482
|
+
description: "Main restoration site coordinates",
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// Also works for collections
|
|
486
|
+
await repo.hypercerts.attachLocationToCollection(collectionUri, locationParams);
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
#### Listing and Retrieving
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
// Get a specific collection
|
|
493
|
+
const collection = await repo.hypercerts.getCollection(collectionUri);
|
|
494
|
+
|
|
495
|
+
// List all collections
|
|
496
|
+
const { records } = await repo.hypercerts.listCollections();
|
|
497
|
+
|
|
498
|
+
// Get a specific project
|
|
499
|
+
const project = await repo.hypercerts.getProject(projectUri);
|
|
500
|
+
|
|
501
|
+
// List all projects
|
|
502
|
+
const { records } = await repo.hypercerts.listProjects();
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
#### Updating Collections and Projects
|
|
506
|
+
|
|
507
|
+
```typescript
|
|
508
|
+
// Update collection
|
|
509
|
+
await repo.hypercerts.updateCollection(collectionUri, {
|
|
510
|
+
title: "Updated Title",
|
|
511
|
+
items: [
|
|
512
|
+
/* updated items */
|
|
513
|
+
],
|
|
514
|
+
avatar: newAvatarBlob, // or null to remove
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// Update project (same API)
|
|
518
|
+
await repo.hypercerts.updateProject(projectUri, {
|
|
519
|
+
shortDescription: "Updated description",
|
|
520
|
+
banner: null, // removes banner
|
|
521
|
+
});
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
#### Deleting
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
// Delete collection
|
|
528
|
+
await repo.hypercerts.deleteCollection(collectionUri);
|
|
529
|
+
|
|
530
|
+
// Delete project
|
|
531
|
+
await repo.hypercerts.deleteProject(projectUri);
|
|
532
|
+
|
|
533
|
+
// Remove location from project
|
|
534
|
+
await repo.hypercerts.removeLocationFromProject(projectUri);
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### 6. Blob Operations (Images & Files)
|
|
322
538
|
|
|
323
539
|
```typescript
|
|
324
540
|
// Upload an image or file
|
|
@@ -329,7 +545,7 @@ console.log("Blob uploaded:", blobResult.ref.$link);
|
|
|
329
545
|
const blobData = await repo.blobs.get("did:plc:user123", "bafyreiabc123...");
|
|
330
546
|
```
|
|
331
547
|
|
|
332
|
-
###
|
|
548
|
+
### 7. Organizations (SDS only)
|
|
333
549
|
|
|
334
550
|
Organizations allow multiple users to collaborate on shared repositories.
|
|
335
551
|
|
|
@@ -357,7 +573,7 @@ const org = await repo.organizations.get("did:plc:org123");
|
|
|
357
573
|
console.log(`${org.name} - ${org.description}`);
|
|
358
574
|
```
|
|
359
575
|
|
|
360
|
-
###
|
|
576
|
+
### 8. Collaborator Management (SDS only)
|
|
361
577
|
|
|
362
578
|
Manage who has access to your repository and what they can do.
|
|
363
579
|
|
|
@@ -426,7 +642,7 @@ await repo.collaborators.transferOwnership({
|
|
|
426
642
|
});
|
|
427
643
|
```
|
|
428
644
|
|
|
429
|
-
###
|
|
645
|
+
### 9. Generic Record Operations
|
|
430
646
|
|
|
431
647
|
For working with any ATProto record type:
|
|
432
648
|
|
|
@@ -471,7 +687,7 @@ const { records, cursor } = await repo.records.list({
|
|
|
471
687
|
});
|
|
472
688
|
```
|
|
473
689
|
|
|
474
|
-
###
|
|
690
|
+
### 10. Profile Management (PDS only)
|
|
475
691
|
|
|
476
692
|
```typescript
|
|
477
693
|
// Get user profile
|
|
@@ -491,40 +707,56 @@ await repo.profile.update({
|
|
|
491
707
|
|
|
492
708
|
### Repository Operations
|
|
493
709
|
|
|
494
|
-
| Operation | Method
|
|
495
|
-
| ------------------ |
|
|
496
|
-
| **Records** |
|
|
497
|
-
| Create record | `repo.records.create()`
|
|
498
|
-
| Get record | `repo.records.get()`
|
|
499
|
-
| Update record | `repo.records.update()`
|
|
500
|
-
| Delete record | `repo.records.delete()`
|
|
501
|
-
| List records | `repo.records.list()`
|
|
502
|
-
| **Hypercerts** |
|
|
503
|
-
| Create hypercert | `repo.hypercerts.create()`
|
|
504
|
-
| Get hypercert | `repo.hypercerts.get()`
|
|
505
|
-
| Update hypercert | `repo.hypercerts.update()`
|
|
506
|
-
| Delete hypercert | `repo.hypercerts.delete()`
|
|
507
|
-
| List hypercerts | `repo.hypercerts.list()`
|
|
508
|
-
| Add contribution | `repo.hypercerts.addContribution()`
|
|
509
|
-
| Add measurement | `repo.hypercerts.addMeasurement()`
|
|
510
|
-
| **
|
|
511
|
-
|
|
|
512
|
-
| Get
|
|
513
|
-
|
|
|
514
|
-
|
|
|
515
|
-
|
|
|
516
|
-
|
|
|
517
|
-
|
|
|
518
|
-
|
|
|
519
|
-
|
|
|
520
|
-
|
|
|
521
|
-
|
|
|
522
|
-
|
|
|
523
|
-
|
|
|
524
|
-
|
|
|
525
|
-
|
|
|
526
|
-
|
|
|
527
|
-
|
|
|
710
|
+
| Operation | Method | PDS | SDS | Returns |
|
|
711
|
+
| ------------------ | ------------------------------------------------ | --- | --- | ---------------------------- |
|
|
712
|
+
| **Records** | | | | |
|
|
713
|
+
| Create record | `repo.records.create()` | ✅ | ✅ | `{ uri, cid }` |
|
|
714
|
+
| Get record | `repo.records.get()` | ✅ | ✅ | Record data |
|
|
715
|
+
| Update record | `repo.records.update()` | ✅ | ✅ | `{ uri, cid }` |
|
|
716
|
+
| Delete record | `repo.records.delete()` | ✅ | ✅ | void |
|
|
717
|
+
| List records | `repo.records.list()` | ✅ | ✅ | `{ records, cursor? }` |
|
|
718
|
+
| **Hypercerts** | | | | |
|
|
719
|
+
| Create hypercert | `repo.hypercerts.create()` | ✅ | ✅ | `{ uri, cid, value }` |
|
|
720
|
+
| Get hypercert | `repo.hypercerts.get()` | ✅ | ✅ | Full hypercert |
|
|
721
|
+
| Update hypercert | `repo.hypercerts.update()` | ✅ | ✅ | `{ uri, cid }` |
|
|
722
|
+
| Delete hypercert | `repo.hypercerts.delete()` | ✅ | ✅ | void |
|
|
723
|
+
| List hypercerts | `repo.hypercerts.list()` | ✅ | ✅ | `{ records, cursor? }` |
|
|
724
|
+
| Add contribution | `repo.hypercerts.addContribution()` | ✅ | ✅ | Contribution |
|
|
725
|
+
| Add measurement | `repo.hypercerts.addMeasurement()` | ✅ | ✅ | Measurement |
|
|
726
|
+
| **Collections** | | | | |
|
|
727
|
+
| Create collection | `repo.hypercerts.createCollection()` | ✅ | ✅ | `{ uri, cid, record }` |
|
|
728
|
+
| Get collection | `repo.hypercerts.getCollection()` | ✅ | ✅ | Collection data |
|
|
729
|
+
| List collections | `repo.hypercerts.listCollections()` | ✅ | ✅ | `{ records, cursor? }` |
|
|
730
|
+
| Update collection | `repo.hypercerts.updateCollection()` | ✅ | ✅ | `{ uri, cid }` |
|
|
731
|
+
| Delete collection | `repo.hypercerts.deleteCollection()` | ✅ | ✅ | void |
|
|
732
|
+
| Attach location | `repo.hypercerts.attachLocationToCollection()` | ✅ | ✅ | `{ uri, cid }` |
|
|
733
|
+
| Remove location | `repo.hypercerts.removeLocationFromCollection()` | ✅ | ✅ | void |
|
|
734
|
+
| **Projects** | | | | |
|
|
735
|
+
| Create project | `repo.hypercerts.createProject()` | ✅ | ✅ | `{ uri, cid, record }` |
|
|
736
|
+
| Get project | `repo.hypercerts.getProject()` | ✅ | ✅ | Project data |
|
|
737
|
+
| List projects | `repo.hypercerts.listProjects()` | ✅ | ✅ | `{ records, cursor? }` |
|
|
738
|
+
| Update project | `repo.hypercerts.updateProject()` | ✅ | ✅ | `{ uri, cid }` |
|
|
739
|
+
| Delete project | `repo.hypercerts.deleteProject()` | ✅ | ✅ | void |
|
|
740
|
+
| Attach location | `repo.hypercerts.attachLocationToProject()` | ✅ | ✅ | `{ uri, cid }` |
|
|
741
|
+
| Remove location | `repo.hypercerts.removeLocationFromProject()` | ✅ | ✅ | void |
|
|
742
|
+
| **Blobs** | | | | |
|
|
743
|
+
| Upload blob | `repo.blobs.upload()` | ✅ | ✅ | `{ ref, mimeType, size }` |
|
|
744
|
+
| Get blob | `repo.blobs.get()` | ✅ | ✅ | Blob data |
|
|
745
|
+
| **Profile** | | | | |
|
|
746
|
+
| Get profile | `repo.profile.get()` | ✅ | ❌ | Profile data |
|
|
747
|
+
| Update profile | `repo.profile.update()` | ✅ | ❌ | void |
|
|
748
|
+
| **Organizations** | | | | |
|
|
749
|
+
| Create org | `repo.organizations.create()` | ❌ | ✅ | `{ did, name, ... }` |
|
|
750
|
+
| Get org | `repo.organizations.get()` | ❌ | ✅ | Organization |
|
|
751
|
+
| List orgs | `repo.organizations.list()` | ❌ | ✅ | `{ organizations, cursor? }` |
|
|
752
|
+
| **Collaborators** | | | | |
|
|
753
|
+
| Grant access | `repo.collaborators.grant()` | ❌ | ✅ | void |
|
|
754
|
+
| Revoke access | `repo.collaborators.revoke()` | ❌ | ✅ | void |
|
|
755
|
+
| List collaborators | `repo.collaborators.list()` | ❌ | ✅ | `{ collaborators, cursor? }` |
|
|
756
|
+
| Check access | `repo.collaborators.hasAccess()` | ❌ | ✅ | boolean |
|
|
757
|
+
| Get role | `repo.collaborators.getRole()` | ❌ | ✅ | Role string |
|
|
758
|
+
| Get permissions | `repo.collaborators.getPermissions()` | ❌ | ✅ | Permissions |
|
|
759
|
+
| Transfer ownership | `repo.collaborators.transferOwnership()` | ❌ | ✅ | void |
|
|
528
760
|
|
|
529
761
|
## Type System
|
|
530
762
|
|
|
@@ -713,20 +945,52 @@ const validationResult = OrgHypercertsClaim.validateMain(claim);
|
|
|
713
945
|
|
|
714
946
|
#### Using LexiconRegistry
|
|
715
947
|
|
|
716
|
-
|
|
948
|
+
The SDK automatically initializes a LexiconRegistry with all hypercert lexicons. You can access it to validate records
|
|
949
|
+
or register custom lexicons:
|
|
717
950
|
|
|
718
951
|
```typescript
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
const registry = new LexiconRegistry();
|
|
722
|
-
registry.registerLexicons(HYPERCERT_LEXICONS);
|
|
952
|
+
// Access the registry from the SDK
|
|
953
|
+
const registry = sdk.getLexiconRegistry();
|
|
723
954
|
|
|
724
955
|
// Validate a record
|
|
725
|
-
const result = registry.validate(
|
|
956
|
+
const result = registry.validate("org.hypercerts.claim.activity", claimData);
|
|
726
957
|
|
|
727
958
|
if (!result.valid) {
|
|
728
959
|
console.error("Invalid record:", result.error);
|
|
729
960
|
}
|
|
961
|
+
|
|
962
|
+
// Register a custom lexicon
|
|
963
|
+
registry.registerFromJSON({
|
|
964
|
+
lexicon: 1,
|
|
965
|
+
id: "org.myapp.customRecord",
|
|
966
|
+
defs: {
|
|
967
|
+
main: {
|
|
968
|
+
type: "record",
|
|
969
|
+
key: "tid",
|
|
970
|
+
record: {
|
|
971
|
+
type: "object",
|
|
972
|
+
required: ["$type", "title"],
|
|
973
|
+
properties: {
|
|
974
|
+
$type: { type: "string", const: "org.myapp.customRecord" },
|
|
975
|
+
title: { type: "string" },
|
|
976
|
+
createdAt: { type: "string", format: "datetime" },
|
|
977
|
+
},
|
|
978
|
+
},
|
|
979
|
+
},
|
|
980
|
+
},
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
// Check if a lexicon is registered
|
|
984
|
+
if (registry.isRegistered("org.myapp.customRecord")) {
|
|
985
|
+
console.log("Custom lexicon is ready to use");
|
|
986
|
+
}
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
You can also access the registry from a Repository instance:
|
|
990
|
+
|
|
991
|
+
```typescript
|
|
992
|
+
const repo = sdk.repository(session);
|
|
993
|
+
const registry = repo.getLexiconRegistry();
|
|
730
994
|
```
|
|
731
995
|
|
|
732
996
|
#### Creating Records with Proper Types
|