@hypercerts-org/sdk-core 0.10.0-beta.0 → 0.10.0-beta.2
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 +281 -0
- package/README.md +97 -114
- package/dist/index.cjs +435 -534
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +160 -271
- package/dist/index.mjs +387 -499
- package/dist/index.mjs.map +1 -1
- package/dist/lexicons.cjs +103 -374
- package/dist/lexicons.cjs.map +1 -1
- package/dist/lexicons.d.ts +90 -188
- package/dist/lexicons.mjs +103 -367
- package/dist/lexicons.mjs.map +1 -1
- package/dist/types.cjs +6 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.ts +24 -37
- package/dist/types.mjs +2 -0
- package/dist/types.mjs.map +1 -1
- package/package.json +10 -9
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { JoseKey, NodeOAuthClient } from '@atproto/oauth-client-node';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { Lexicons } from '@atproto/lexicon';
|
|
4
|
-
import { HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS } from '@hypercerts-org/lexicon';
|
|
5
|
-
export { AppCertifiedLocation, ComAtprotoRepoStrongRef, HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS, OrgHypercertsClaim, OrgHypercertsClaimContribution, OrgHypercertsClaimEvaluation, OrgHypercertsClaimEvidence, OrgHypercertsClaimMeasurement, OrgHypercertsClaimRights, OrgHypercertsCollection, ids, lexicons, schemaDict, schemas, validate } from '@hypercerts-org/lexicon';
|
|
6
3
|
import { Agent } from '@atproto/api';
|
|
7
4
|
import { EventEmitter } from 'eventemitter3';
|
|
5
|
+
import { CERTIFIED_DEFS_LEXICON_JSON, LOCATION_LEXICON_JSON, STRONGREF_LEXICON_JSON, HYPERCERTS_DEFS_LEXICON_JSON, ACTIVITY_LEXICON_JSON, COLLECTION_LEXICON_JSON, CONTRIBUTION_LEXICON_JSON, EVALUATION_LEXICON_JSON, EVIDENCE_LEXICON_JSON, MEASUREMENT_LEXICON_JSON, RIGHTS_LEXICON_JSON, PROJECT_LEXICON_JSON, BADGE_AWARD_LEXICON_JSON, BADGE_DEFINITION_LEXICON_JSON, BADGE_RESPONSE_LEXICON_JSON, FUNDING_RECEIPT_LEXICON_JSON, FUNDING_RECEIPT_NSID, BADGE_RESPONSE_NSID, BADGE_DEFINITION_NSID, BADGE_AWARD_NSID, PROJECT_NSID, COLLECTION_NSID, EVIDENCE_NSID, EVALUATION_NSID, MEASUREMENT_NSID, CONTRIBUTION_NSID, LOCATION_NSID, RIGHTS_NSID, ACTIVITY_NSID, validate } from '@hypercerts-org/lexicon';
|
|
6
|
+
export { AppCertifiedBadgeAward, AppCertifiedBadgeDefinition, AppCertifiedBadgeResponse, AppCertifiedLocation, ComAtprotoRepoStrongRef, HYPERCERTS_NSIDS, HYPERCERTS_NSIDS_BY_TYPE, HYPERCERTS_SCHEMAS, HYPERCERTS_SCHEMA_DICT, OrgHypercertsClaimActivity, OrgHypercertsClaimCollection, OrgHypercertsClaimContribution, OrgHypercertsClaimEvaluation, OrgHypercertsClaimEvidence, OrgHypercertsClaimMeasurement, OrgHypercertsClaimProject, OrgHypercertsClaimRights, OrgHypercertsFundingReceipt, validate } from '@hypercerts-org/lexicon';
|
|
7
|
+
import '@atproto/lexicon';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Base error class for all SDK errors.
|
|
@@ -2003,303 +2003,6 @@ class OAuthClient {
|
|
|
2003
2003
|
}
|
|
2004
2004
|
}
|
|
2005
2005
|
|
|
2006
|
-
/**
|
|
2007
|
-
* Registry for managing and validating AT Protocol lexicon schemas.
|
|
2008
|
-
*
|
|
2009
|
-
* Lexicons are schema definitions that describe the structure of records
|
|
2010
|
-
* in the AT Protocol. This registry allows you to:
|
|
2011
|
-
*
|
|
2012
|
-
* - Register custom lexicons for your application's record types
|
|
2013
|
-
* - Validate records against their lexicon schemas
|
|
2014
|
-
* - Extend the AT Protocol Agent with custom lexicon support
|
|
2015
|
-
*
|
|
2016
|
-
* @remarks
|
|
2017
|
-
* The SDK automatically registers hypercert lexicons when creating a Repository.
|
|
2018
|
-
* You only need to use this class directly if you're working with custom
|
|
2019
|
-
* record types.
|
|
2020
|
-
*
|
|
2021
|
-
* **Lexicon IDs** follow the NSID (Namespaced Identifier) format:
|
|
2022
|
-
* `{authority}.{name}` (e.g., `org.hypercerts.hypercert`)
|
|
2023
|
-
*
|
|
2024
|
-
* @example Registering custom lexicons
|
|
2025
|
-
* ```typescript
|
|
2026
|
-
* const registry = sdk.getLexiconRegistry();
|
|
2027
|
-
*
|
|
2028
|
-
* // Register a single lexicon
|
|
2029
|
-
* registry.register({
|
|
2030
|
-
* lexicon: 1,
|
|
2031
|
-
* id: "org.example.myRecord",
|
|
2032
|
-
* defs: {
|
|
2033
|
-
* main: {
|
|
2034
|
-
* type: "record",
|
|
2035
|
-
* key: "tid",
|
|
2036
|
-
* record: {
|
|
2037
|
-
* type: "object",
|
|
2038
|
-
* required: ["title", "createdAt"],
|
|
2039
|
-
* properties: {
|
|
2040
|
-
* title: { type: "string" },
|
|
2041
|
-
* description: { type: "string" },
|
|
2042
|
-
* createdAt: { type: "string", format: "datetime" },
|
|
2043
|
-
* },
|
|
2044
|
-
* },
|
|
2045
|
-
* },
|
|
2046
|
-
* },
|
|
2047
|
-
* });
|
|
2048
|
-
*
|
|
2049
|
-
* // Register multiple lexicons at once
|
|
2050
|
-
* registry.registerMany([lexicon1, lexicon2, lexicon3]);
|
|
2051
|
-
* ```
|
|
2052
|
-
*
|
|
2053
|
-
* @example Validating records
|
|
2054
|
-
* ```typescript
|
|
2055
|
-
* const result = registry.validate("org.example.myRecord", {
|
|
2056
|
-
* title: "Test",
|
|
2057
|
-
* createdAt: new Date().toISOString(),
|
|
2058
|
-
* });
|
|
2059
|
-
*
|
|
2060
|
-
* if (!result.valid) {
|
|
2061
|
-
* console.error(`Validation failed: ${result.error}`);
|
|
2062
|
-
* }
|
|
2063
|
-
* ```
|
|
2064
|
-
*
|
|
2065
|
-
* @see https://atproto.com/specs/lexicon for the Lexicon specification
|
|
2066
|
-
*/
|
|
2067
|
-
class LexiconRegistry {
|
|
2068
|
-
/**
|
|
2069
|
-
* Creates a new LexiconRegistry.
|
|
2070
|
-
*
|
|
2071
|
-
* The registry starts empty. Use {@link register} or {@link registerMany}
|
|
2072
|
-
* to add lexicons.
|
|
2073
|
-
*/
|
|
2074
|
-
constructor() {
|
|
2075
|
-
/** Map of lexicon ID to lexicon document */
|
|
2076
|
-
this.lexicons = new Map();
|
|
2077
|
-
this.lexiconsCollection = new Lexicons();
|
|
2078
|
-
}
|
|
2079
|
-
/**
|
|
2080
|
-
* Registers a single lexicon schema.
|
|
2081
|
-
*
|
|
2082
|
-
* @param lexicon - The lexicon document to register
|
|
2083
|
-
* @throws {@link ValidationError} if the lexicon doesn't have an `id` field
|
|
2084
|
-
*
|
|
2085
|
-
* @remarks
|
|
2086
|
-
* If a lexicon with the same ID is already registered, it will be
|
|
2087
|
-
* replaced with the new definition. This is useful for testing but
|
|
2088
|
-
* should generally be avoided in production.
|
|
2089
|
-
*
|
|
2090
|
-
* @example
|
|
2091
|
-
* ```typescript
|
|
2092
|
-
* registry.register({
|
|
2093
|
-
* lexicon: 1,
|
|
2094
|
-
* id: "org.example.post",
|
|
2095
|
-
* defs: {
|
|
2096
|
-
* main: {
|
|
2097
|
-
* type: "record",
|
|
2098
|
-
* key: "tid",
|
|
2099
|
-
* record: {
|
|
2100
|
-
* type: "object",
|
|
2101
|
-
* required: ["text", "createdAt"],
|
|
2102
|
-
* properties: {
|
|
2103
|
-
* text: { type: "string", maxLength: 300 },
|
|
2104
|
-
* createdAt: { type: "string", format: "datetime" },
|
|
2105
|
-
* },
|
|
2106
|
-
* },
|
|
2107
|
-
* },
|
|
2108
|
-
* },
|
|
2109
|
-
* });
|
|
2110
|
-
* ```
|
|
2111
|
-
*/
|
|
2112
|
-
register(lexicon) {
|
|
2113
|
-
if (!lexicon.id) {
|
|
2114
|
-
throw new ValidationError("Lexicon must have an 'id' field");
|
|
2115
|
-
}
|
|
2116
|
-
// Remove existing lexicon if present (to allow overwriting)
|
|
2117
|
-
if (this.lexicons.has(lexicon.id)) {
|
|
2118
|
-
// Lexicons collection doesn't support removal, so we create a new one
|
|
2119
|
-
// This is a limitation - in practice, lexicons shouldn't be overwritten
|
|
2120
|
-
// But we allow it for testing and flexibility
|
|
2121
|
-
const existingLexicon = this.lexicons.get(lexicon.id);
|
|
2122
|
-
if (existingLexicon) {
|
|
2123
|
-
// Try to remove from collection (may fail if not supported)
|
|
2124
|
-
try {
|
|
2125
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2126
|
-
this.lexiconsCollection.remove?.(lexicon.id);
|
|
2127
|
-
}
|
|
2128
|
-
catch {
|
|
2129
|
-
// If removal fails, create a new collection
|
|
2130
|
-
this.lexiconsCollection = new Lexicons();
|
|
2131
|
-
// Re-register all other lexicons
|
|
2132
|
-
for (const [id, lex] of this.lexicons.entries()) {
|
|
2133
|
-
if (id !== lexicon.id) {
|
|
2134
|
-
this.lexiconsCollection.add(lex);
|
|
2135
|
-
}
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
}
|
|
2139
|
-
}
|
|
2140
|
-
this.lexicons.set(lexicon.id, lexicon);
|
|
2141
|
-
this.lexiconsCollection.add(lexicon);
|
|
2142
|
-
}
|
|
2143
|
-
/**
|
|
2144
|
-
* Registers multiple lexicons at once.
|
|
2145
|
-
*
|
|
2146
|
-
* @param lexicons - Array of lexicon documents to register
|
|
2147
|
-
*
|
|
2148
|
-
* @example
|
|
2149
|
-
* ```typescript
|
|
2150
|
-
* import { HYPERCERT_LEXICONS } from "@hypercerts-org/sdk/lexicons";
|
|
2151
|
-
*
|
|
2152
|
-
* registry.registerMany(HYPERCERT_LEXICONS);
|
|
2153
|
-
* ```
|
|
2154
|
-
*/
|
|
2155
|
-
registerMany(lexicons) {
|
|
2156
|
-
for (const lexicon of lexicons) {
|
|
2157
|
-
this.register(lexicon);
|
|
2158
|
-
}
|
|
2159
|
-
}
|
|
2160
|
-
/**
|
|
2161
|
-
* Gets a lexicon document by ID.
|
|
2162
|
-
*
|
|
2163
|
-
* @param id - The lexicon NSID (e.g., "org.hypercerts.hypercert")
|
|
2164
|
-
* @returns The lexicon document, or `undefined` if not registered
|
|
2165
|
-
*
|
|
2166
|
-
* @example
|
|
2167
|
-
* ```typescript
|
|
2168
|
-
* const lexicon = registry.get("org.hypercerts.hypercert");
|
|
2169
|
-
* if (lexicon) {
|
|
2170
|
-
* console.log(`Found lexicon: ${lexicon.id}`);
|
|
2171
|
-
* }
|
|
2172
|
-
* ```
|
|
2173
|
-
*/
|
|
2174
|
-
get(id) {
|
|
2175
|
-
return this.lexicons.get(id);
|
|
2176
|
-
}
|
|
2177
|
-
/**
|
|
2178
|
-
* Validates a record against a collection's lexicon schema.
|
|
2179
|
-
*
|
|
2180
|
-
* @param collection - The collection NSID (same as lexicon ID)
|
|
2181
|
-
* @param record - The record data to validate
|
|
2182
|
-
* @returns Validation result with `valid` boolean and optional `error` message
|
|
2183
|
-
*
|
|
2184
|
-
* @remarks
|
|
2185
|
-
* - If no lexicon is registered for the collection, validation passes
|
|
2186
|
-
* (we can't validate against unknown schemas)
|
|
2187
|
-
* - Validation checks required fields and type constraints defined
|
|
2188
|
-
* in the lexicon schema
|
|
2189
|
-
*
|
|
2190
|
-
* @example
|
|
2191
|
-
* ```typescript
|
|
2192
|
-
* const result = registry.validate("org.hypercerts.hypercert", {
|
|
2193
|
-
* title: "My Hypercert",
|
|
2194
|
-
* description: "Description...",
|
|
2195
|
-
* // ... other fields
|
|
2196
|
-
* });
|
|
2197
|
-
*
|
|
2198
|
-
* if (!result.valid) {
|
|
2199
|
-
* throw new Error(`Invalid record: ${result.error}`);
|
|
2200
|
-
* }
|
|
2201
|
-
* ```
|
|
2202
|
-
*/
|
|
2203
|
-
validate(collection, record) {
|
|
2204
|
-
// Check if we have a lexicon registered for this collection
|
|
2205
|
-
// Collection format is typically "namespace.collection" (e.g., "app.bsky.feed.post")
|
|
2206
|
-
// Lexicon ID format is the same
|
|
2207
|
-
const lexiconId = collection;
|
|
2208
|
-
const lexicon = this.lexicons.get(lexiconId);
|
|
2209
|
-
if (!lexicon) {
|
|
2210
|
-
// No lexicon registered - validation passes (can't validate unknown schemas)
|
|
2211
|
-
return { valid: true };
|
|
2212
|
-
}
|
|
2213
|
-
// Check required fields if the lexicon defines them
|
|
2214
|
-
const recordDef = lexicon.defs?.record;
|
|
2215
|
-
if (recordDef && typeof recordDef === "object" && "record" in recordDef) {
|
|
2216
|
-
const recordSchema = recordDef.record;
|
|
2217
|
-
if (typeof recordSchema === "object" && "required" in recordSchema && Array.isArray(recordSchema.required)) {
|
|
2218
|
-
const recordObj = record;
|
|
2219
|
-
for (const requiredField of recordSchema.required) {
|
|
2220
|
-
if (typeof requiredField === "string" && !(requiredField in recordObj)) {
|
|
2221
|
-
return {
|
|
2222
|
-
valid: false,
|
|
2223
|
-
error: `Missing required field: ${requiredField}`,
|
|
2224
|
-
};
|
|
2225
|
-
}
|
|
2226
|
-
}
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2229
|
-
try {
|
|
2230
|
-
this.lexiconsCollection.assertValidRecord(collection, record);
|
|
2231
|
-
return { valid: true };
|
|
2232
|
-
}
|
|
2233
|
-
catch (error) {
|
|
2234
|
-
// If error indicates lexicon not found, treat as validation pass
|
|
2235
|
-
// (the lexicon might exist in Agent's collection but not ours)
|
|
2236
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2237
|
-
if (errorMessage.includes("not found") || errorMessage.includes("Lexicon not found")) {
|
|
2238
|
-
return { valid: true };
|
|
2239
|
-
}
|
|
2240
|
-
return {
|
|
2241
|
-
valid: false,
|
|
2242
|
-
error: errorMessage,
|
|
2243
|
-
};
|
|
2244
|
-
}
|
|
2245
|
-
}
|
|
2246
|
-
/**
|
|
2247
|
-
* Adds all registered lexicons to an AT Protocol Agent instance.
|
|
2248
|
-
*
|
|
2249
|
-
* This allows the Agent to understand custom lexicon types when making
|
|
2250
|
-
* API requests.
|
|
2251
|
-
*
|
|
2252
|
-
* @param agent - The Agent instance to extend
|
|
2253
|
-
*
|
|
2254
|
-
* @remarks
|
|
2255
|
-
* This is called automatically when creating a Repository. You typically
|
|
2256
|
-
* don't need to call this directly unless you're using the Agent
|
|
2257
|
-
* independently.
|
|
2258
|
-
*
|
|
2259
|
-
* @internal
|
|
2260
|
-
*/
|
|
2261
|
-
addToAgent(agent) {
|
|
2262
|
-
// Access the internal lexicons collection and merge our lexicons
|
|
2263
|
-
// The Agent's lex property is a Lexicons instance
|
|
2264
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2265
|
-
const agentLex = agent.lex;
|
|
2266
|
-
// Add each registered lexicon to the agent
|
|
2267
|
-
for (const lexicon of this.lexicons.values()) {
|
|
2268
|
-
agentLex.add(lexicon);
|
|
2269
|
-
}
|
|
2270
|
-
}
|
|
2271
|
-
/**
|
|
2272
|
-
* Gets all registered lexicon IDs.
|
|
2273
|
-
*
|
|
2274
|
-
* @returns Array of lexicon NSIDs
|
|
2275
|
-
*
|
|
2276
|
-
* @example
|
|
2277
|
-
* ```typescript
|
|
2278
|
-
* const ids = registry.getRegisteredIds();
|
|
2279
|
-
* console.log(`Registered lexicons: ${ids.join(", ")}`);
|
|
2280
|
-
* ```
|
|
2281
|
-
*/
|
|
2282
|
-
getRegisteredIds() {
|
|
2283
|
-
return Array.from(this.lexicons.keys());
|
|
2284
|
-
}
|
|
2285
|
-
/**
|
|
2286
|
-
* Checks if a lexicon is registered.
|
|
2287
|
-
*
|
|
2288
|
-
* @param id - The lexicon NSID to check
|
|
2289
|
-
* @returns `true` if the lexicon is registered
|
|
2290
|
-
*
|
|
2291
|
-
* @example
|
|
2292
|
-
* ```typescript
|
|
2293
|
-
* if (registry.has("org.hypercerts.hypercert")) {
|
|
2294
|
-
* // Hypercert lexicon is available
|
|
2295
|
-
* }
|
|
2296
|
-
* ```
|
|
2297
|
-
*/
|
|
2298
|
-
has(id) {
|
|
2299
|
-
return this.lexicons.has(id);
|
|
2300
|
-
}
|
|
2301
|
-
}
|
|
2302
|
-
|
|
2303
2006
|
/**
|
|
2304
2007
|
* ConfigurableAgent - Agent with configurable service URL routing.
|
|
2305
2008
|
*
|
|
@@ -2428,14 +2131,12 @@ class RecordOperationsImpl {
|
|
|
2428
2131
|
*
|
|
2429
2132
|
* @param agent - AT Protocol Agent for making API calls
|
|
2430
2133
|
* @param repoDid - DID of the repository to operate on
|
|
2431
|
-
* @param lexiconRegistry - Registry for record validation
|
|
2432
2134
|
*
|
|
2433
2135
|
* @internal
|
|
2434
2136
|
*/
|
|
2435
|
-
constructor(agent, repoDid
|
|
2137
|
+
constructor(agent, repoDid) {
|
|
2436
2138
|
this.agent = agent;
|
|
2437
2139
|
this.repoDid = repoDid;
|
|
2438
|
-
this.lexiconRegistry = lexiconRegistry;
|
|
2439
2140
|
}
|
|
2440
2141
|
/**
|
|
2441
2142
|
* Creates a new record in the specified collection.
|
|
@@ -2471,10 +2172,6 @@ class RecordOperationsImpl {
|
|
|
2471
2172
|
* ```
|
|
2472
2173
|
*/
|
|
2473
2174
|
async create(params) {
|
|
2474
|
-
const validation = this.lexiconRegistry.validate(params.collection, params.record);
|
|
2475
|
-
if (!validation.valid) {
|
|
2476
|
-
throw new ValidationError(`Invalid record for collection ${params.collection}: ${validation.error}`);
|
|
2477
|
-
}
|
|
2478
2175
|
try {
|
|
2479
2176
|
const result = await this.agent.com.atproto.repo.createRecord({
|
|
2480
2177
|
repo: this.repoDid,
|
|
@@ -2529,10 +2226,6 @@ class RecordOperationsImpl {
|
|
|
2529
2226
|
* ```
|
|
2530
2227
|
*/
|
|
2531
2228
|
async update(params) {
|
|
2532
|
-
const validation = this.lexiconRegistry.validate(params.collection, params.record);
|
|
2533
|
-
if (!validation.valid) {
|
|
2534
|
-
throw new ValidationError(`Invalid record for collection ${params.collection}: ${validation.error}`);
|
|
2535
|
-
}
|
|
2536
2229
|
try {
|
|
2537
2230
|
const result = await this.agent.com.atproto.repo.putRecord({
|
|
2538
2231
|
repo: this.repoDid,
|
|
@@ -3124,6 +2817,148 @@ class ProfileOperationsImpl {
|
|
|
3124
2817
|
}
|
|
3125
2818
|
}
|
|
3126
2819
|
|
|
2820
|
+
/**
|
|
2821
|
+
* Lexicons entrypoint - Lexicon definitions and registry.
|
|
2822
|
+
*
|
|
2823
|
+
* This sub-entrypoint exports the lexicon registry and hypercert
|
|
2824
|
+
* lexicon constants for working with AT Protocol record schemas.
|
|
2825
|
+
*
|
|
2826
|
+
* @remarks
|
|
2827
|
+
* Import from `@hypercerts-org/sdk/lexicons`:
|
|
2828
|
+
*
|
|
2829
|
+
* ```typescript
|
|
2830
|
+
* import {
|
|
2831
|
+
* LexiconRegistry,
|
|
2832
|
+
* HYPERCERT_LEXICONS,
|
|
2833
|
+
* HYPERCERT_COLLECTIONS,
|
|
2834
|
+
* } from "@hypercerts-org/sdk/lexicons";
|
|
2835
|
+
* ```
|
|
2836
|
+
*
|
|
2837
|
+
* **Exports**:
|
|
2838
|
+
* - {@link LexiconRegistry} - Registry for managing and validating lexicons
|
|
2839
|
+
* - {@link HYPERCERT_LEXICONS} - Array of all hypercert lexicon documents
|
|
2840
|
+
* - {@link HYPERCERT_COLLECTIONS} - Constants for collection NSIDs
|
|
2841
|
+
*
|
|
2842
|
+
* @example Using collection constants
|
|
2843
|
+
* ```typescript
|
|
2844
|
+
* import { HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk/lexicons";
|
|
2845
|
+
*
|
|
2846
|
+
* // List hypercerts using the correct collection name
|
|
2847
|
+
* const records = await repo.records.list({
|
|
2848
|
+
* collection: HYPERCERT_COLLECTIONS.RECORD,
|
|
2849
|
+
* });
|
|
2850
|
+
*
|
|
2851
|
+
* // List contributions
|
|
2852
|
+
* const contributions = await repo.records.list({
|
|
2853
|
+
* collection: HYPERCERT_COLLECTIONS.CONTRIBUTION,
|
|
2854
|
+
* });
|
|
2855
|
+
* ```
|
|
2856
|
+
*
|
|
2857
|
+
* @example Custom lexicon registration
|
|
2858
|
+
* ```typescript
|
|
2859
|
+
* import { LexiconRegistry } from "@hypercerts-org/sdk/lexicons";
|
|
2860
|
+
*
|
|
2861
|
+
* const registry = sdk.getLexiconRegistry();
|
|
2862
|
+
*
|
|
2863
|
+
* // Register custom lexicon
|
|
2864
|
+
* registry.register({
|
|
2865
|
+
* lexicon: 1,
|
|
2866
|
+
* id: "org.myapp.customRecord",
|
|
2867
|
+
* defs: { ... },
|
|
2868
|
+
* });
|
|
2869
|
+
*
|
|
2870
|
+
* // Validate a record
|
|
2871
|
+
* const result = registry.validate("org.myapp.customRecord", record);
|
|
2872
|
+
* if (!result.valid) {
|
|
2873
|
+
* console.error(result.error);
|
|
2874
|
+
* }
|
|
2875
|
+
* ```
|
|
2876
|
+
*
|
|
2877
|
+
* @packageDocumentation
|
|
2878
|
+
*/
|
|
2879
|
+
/**
|
|
2880
|
+
* All hypercert-related lexicons for registration with AT Protocol Agent.
|
|
2881
|
+
* This array contains all lexicon documents from the published package.
|
|
2882
|
+
*/
|
|
2883
|
+
const HYPERCERT_LEXICONS = [
|
|
2884
|
+
CERTIFIED_DEFS_LEXICON_JSON,
|
|
2885
|
+
LOCATION_LEXICON_JSON,
|
|
2886
|
+
STRONGREF_LEXICON_JSON,
|
|
2887
|
+
HYPERCERTS_DEFS_LEXICON_JSON,
|
|
2888
|
+
ACTIVITY_LEXICON_JSON,
|
|
2889
|
+
COLLECTION_LEXICON_JSON,
|
|
2890
|
+
CONTRIBUTION_LEXICON_JSON,
|
|
2891
|
+
EVALUATION_LEXICON_JSON,
|
|
2892
|
+
EVIDENCE_LEXICON_JSON,
|
|
2893
|
+
MEASUREMENT_LEXICON_JSON,
|
|
2894
|
+
RIGHTS_LEXICON_JSON,
|
|
2895
|
+
PROJECT_LEXICON_JSON,
|
|
2896
|
+
BADGE_AWARD_LEXICON_JSON,
|
|
2897
|
+
BADGE_DEFINITION_LEXICON_JSON,
|
|
2898
|
+
BADGE_RESPONSE_LEXICON_JSON,
|
|
2899
|
+
FUNDING_RECEIPT_LEXICON_JSON,
|
|
2900
|
+
];
|
|
2901
|
+
/**
|
|
2902
|
+
* Collection NSIDs (Namespaced Identifiers) for hypercert records.
|
|
2903
|
+
*
|
|
2904
|
+
* Use these constants when performing record operations to ensure
|
|
2905
|
+
* correct collection names.
|
|
2906
|
+
*/
|
|
2907
|
+
const HYPERCERT_COLLECTIONS = {
|
|
2908
|
+
/**
|
|
2909
|
+
* Main hypercert claim record collection.
|
|
2910
|
+
*/
|
|
2911
|
+
CLAIM: ACTIVITY_NSID,
|
|
2912
|
+
/**
|
|
2913
|
+
* Rights record collection.
|
|
2914
|
+
*/
|
|
2915
|
+
RIGHTS: RIGHTS_NSID,
|
|
2916
|
+
/**
|
|
2917
|
+
* Location record collection (shared certified lexicon).
|
|
2918
|
+
*/
|
|
2919
|
+
LOCATION: LOCATION_NSID,
|
|
2920
|
+
/**
|
|
2921
|
+
* Contribution record collection.
|
|
2922
|
+
*/
|
|
2923
|
+
CONTRIBUTION: CONTRIBUTION_NSID,
|
|
2924
|
+
/**
|
|
2925
|
+
* Measurement record collection.
|
|
2926
|
+
*/
|
|
2927
|
+
MEASUREMENT: MEASUREMENT_NSID,
|
|
2928
|
+
/**
|
|
2929
|
+
* Evaluation record collection.
|
|
2930
|
+
*/
|
|
2931
|
+
EVALUATION: EVALUATION_NSID,
|
|
2932
|
+
/**
|
|
2933
|
+
* Evidence record collection.
|
|
2934
|
+
*/
|
|
2935
|
+
EVIDENCE: EVIDENCE_NSID,
|
|
2936
|
+
/**
|
|
2937
|
+
* Collection record collection (groups of hypercerts).
|
|
2938
|
+
*/
|
|
2939
|
+
COLLECTION: COLLECTION_NSID,
|
|
2940
|
+
/**
|
|
2941
|
+
* Project record collection.
|
|
2942
|
+
*/
|
|
2943
|
+
PROJECT: PROJECT_NSID,
|
|
2944
|
+
/**
|
|
2945
|
+
* Badge award record collection.
|
|
2946
|
+
*/
|
|
2947
|
+
BADGE_AWARD: BADGE_AWARD_NSID,
|
|
2948
|
+
/**
|
|
2949
|
+
* Badge definition record collection.
|
|
2950
|
+
*/
|
|
2951
|
+
BADGE_DEFINITION: BADGE_DEFINITION_NSID,
|
|
2952
|
+
/**
|
|
2953
|
+
* Badge response record collection.
|
|
2954
|
+
*/
|
|
2955
|
+
BADGE_RESPONSE: BADGE_RESPONSE_NSID,
|
|
2956
|
+
/**
|
|
2957
|
+
* Funding receipt record collection.
|
|
2958
|
+
*/
|
|
2959
|
+
FUNDING_RECEIPT: FUNDING_RECEIPT_NSID,
|
|
2960
|
+
};
|
|
2961
|
+
|
|
3127
2962
|
/**
|
|
3128
2963
|
* HypercertOperationsImpl - High-level hypercert operations.
|
|
3129
2964
|
*
|
|
@@ -3187,17 +3022,15 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
3187
3022
|
* @param agent - AT Protocol Agent for making API calls
|
|
3188
3023
|
* @param repoDid - DID of the repository to operate on
|
|
3189
3024
|
* @param _serverUrl - Server URL (reserved for future use)
|
|
3190
|
-
* @param lexiconRegistry - Registry for record validation
|
|
3191
3025
|
* @param logger - Optional logger for debugging
|
|
3192
3026
|
*
|
|
3193
3027
|
* @internal
|
|
3194
3028
|
*/
|
|
3195
|
-
constructor(agent, repoDid, _serverUrl,
|
|
3029
|
+
constructor(agent, repoDid, _serverUrl, logger) {
|
|
3196
3030
|
super();
|
|
3197
3031
|
this.agent = agent;
|
|
3198
3032
|
this.repoDid = repoDid;
|
|
3199
3033
|
this._serverUrl = _serverUrl;
|
|
3200
|
-
this.lexiconRegistry = lexiconRegistry;
|
|
3201
3034
|
this.logger = logger;
|
|
3202
3035
|
}
|
|
3203
3036
|
/**
|
|
@@ -3217,6 +3050,202 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
3217
3050
|
}
|
|
3218
3051
|
}
|
|
3219
3052
|
}
|
|
3053
|
+
/**
|
|
3054
|
+
* Uploads an image blob and returns a blob reference.
|
|
3055
|
+
*
|
|
3056
|
+
* @param image - Image blob to upload
|
|
3057
|
+
* @param onProgress - Optional progress callback
|
|
3058
|
+
* @returns Promise resolving to blob reference or undefined
|
|
3059
|
+
* @throws {@link NetworkError} if upload fails
|
|
3060
|
+
* @internal
|
|
3061
|
+
*/
|
|
3062
|
+
async uploadImageBlob(image, onProgress) {
|
|
3063
|
+
this.emitProgress(onProgress, { name: "uploadImage", status: "start" });
|
|
3064
|
+
try {
|
|
3065
|
+
const arrayBuffer = await image.arrayBuffer();
|
|
3066
|
+
const uint8Array = new Uint8Array(arrayBuffer);
|
|
3067
|
+
const uploadResult = await this.agent.com.atproto.repo.uploadBlob(uint8Array, {
|
|
3068
|
+
encoding: image.type || "image/jpeg",
|
|
3069
|
+
});
|
|
3070
|
+
if (uploadResult.success) {
|
|
3071
|
+
const blobRef = {
|
|
3072
|
+
$type: "blob",
|
|
3073
|
+
ref: { $link: uploadResult.data.blob.ref.toString() },
|
|
3074
|
+
mimeType: uploadResult.data.blob.mimeType,
|
|
3075
|
+
size: uploadResult.data.blob.size,
|
|
3076
|
+
};
|
|
3077
|
+
this.emitProgress(onProgress, {
|
|
3078
|
+
name: "uploadImage",
|
|
3079
|
+
status: "success",
|
|
3080
|
+
data: { size: image.size },
|
|
3081
|
+
});
|
|
3082
|
+
return blobRef;
|
|
3083
|
+
}
|
|
3084
|
+
throw new NetworkError("Image upload succeeded but returned no blob reference");
|
|
3085
|
+
}
|
|
3086
|
+
catch (error) {
|
|
3087
|
+
this.emitProgress(onProgress, { name: "uploadImage", status: "error", error: error });
|
|
3088
|
+
throw new NetworkError(`Failed to upload image: ${error instanceof Error ? error.message : "Unknown"}`, error);
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
/**
|
|
3092
|
+
* Creates a rights record for a hypercert.
|
|
3093
|
+
*
|
|
3094
|
+
* @param rights - Rights data
|
|
3095
|
+
* @param createdAt - ISO timestamp for creation
|
|
3096
|
+
* @param onProgress - Optional progress callback
|
|
3097
|
+
* @returns Promise resolving to rights URI and CID
|
|
3098
|
+
* @throws {@link ValidationError} if validation fails
|
|
3099
|
+
* @throws {@link NetworkError} if creation fails
|
|
3100
|
+
* @internal
|
|
3101
|
+
*/
|
|
3102
|
+
async createRightsRecord(rights, createdAt, onProgress) {
|
|
3103
|
+
this.emitProgress(onProgress, { name: "createRights", status: "start" });
|
|
3104
|
+
const rightsRecord = {
|
|
3105
|
+
$type: HYPERCERT_COLLECTIONS.RIGHTS,
|
|
3106
|
+
rightsName: rights.name,
|
|
3107
|
+
rightsType: rights.type,
|
|
3108
|
+
rightsDescription: rights.description,
|
|
3109
|
+
createdAt,
|
|
3110
|
+
};
|
|
3111
|
+
const rightsValidation = validate(rightsRecord, HYPERCERT_COLLECTIONS.RIGHTS, "main", false);
|
|
3112
|
+
if (!rightsValidation.success) {
|
|
3113
|
+
throw new ValidationError(`Invalid rights record: ${rightsValidation.error?.message}`);
|
|
3114
|
+
}
|
|
3115
|
+
const rightsResult = await this.agent.com.atproto.repo.createRecord({
|
|
3116
|
+
repo: this.repoDid,
|
|
3117
|
+
collection: HYPERCERT_COLLECTIONS.RIGHTS,
|
|
3118
|
+
record: rightsRecord,
|
|
3119
|
+
});
|
|
3120
|
+
if (!rightsResult.success) {
|
|
3121
|
+
throw new NetworkError("Failed to create rights record");
|
|
3122
|
+
}
|
|
3123
|
+
const uri = rightsResult.data.uri;
|
|
3124
|
+
const cid = rightsResult.data.cid;
|
|
3125
|
+
this.emit("rightsCreated", { uri, cid });
|
|
3126
|
+
this.emitProgress(onProgress, {
|
|
3127
|
+
name: "createRights",
|
|
3128
|
+
status: "success",
|
|
3129
|
+
data: { uri },
|
|
3130
|
+
});
|
|
3131
|
+
return { uri, cid };
|
|
3132
|
+
}
|
|
3133
|
+
/**
|
|
3134
|
+
* Creates the main hypercert record.
|
|
3135
|
+
*
|
|
3136
|
+
* @param params - Hypercert creation parameters
|
|
3137
|
+
* @param rightsUri - URI of the associated rights record
|
|
3138
|
+
* @param rightsCid - CID of the associated rights record
|
|
3139
|
+
* @param imageBlobRef - Optional image blob reference
|
|
3140
|
+
* @param createdAt - ISO timestamp for creation
|
|
3141
|
+
* @param onProgress - Optional progress callback
|
|
3142
|
+
* @returns Promise resolving to hypercert URI and CID
|
|
3143
|
+
* @throws {@link ValidationError} if validation fails
|
|
3144
|
+
* @throws {@link NetworkError} if creation fails
|
|
3145
|
+
* @internal
|
|
3146
|
+
*/
|
|
3147
|
+
async createHypercertRecord(params, rightsUri, rightsCid, imageBlobRef, createdAt, onProgress) {
|
|
3148
|
+
this.emitProgress(onProgress, { name: "createHypercert", status: "start" });
|
|
3149
|
+
const hypercertRecord = {
|
|
3150
|
+
$type: HYPERCERT_COLLECTIONS.CLAIM,
|
|
3151
|
+
title: params.title,
|
|
3152
|
+
shortDescription: params.shortDescription,
|
|
3153
|
+
description: params.description,
|
|
3154
|
+
workScope: params.workScope,
|
|
3155
|
+
workTimeFrameFrom: params.workTimeFrameFrom,
|
|
3156
|
+
workTimeFrameTo: params.workTimeFrameTo,
|
|
3157
|
+
rights: { uri: rightsUri, cid: rightsCid },
|
|
3158
|
+
createdAt,
|
|
3159
|
+
};
|
|
3160
|
+
if (imageBlobRef) {
|
|
3161
|
+
hypercertRecord.image = imageBlobRef;
|
|
3162
|
+
}
|
|
3163
|
+
if (params.evidence && params.evidence.length > 0) {
|
|
3164
|
+
hypercertRecord.evidence = params.evidence;
|
|
3165
|
+
}
|
|
3166
|
+
const hypercertValidation = validate(hypercertRecord, HYPERCERT_COLLECTIONS.CLAIM, "#main", false);
|
|
3167
|
+
if (!hypercertValidation.success) {
|
|
3168
|
+
throw new ValidationError(`Invalid hypercert record: ${hypercertValidation.error?.message}`);
|
|
3169
|
+
}
|
|
3170
|
+
const hypercertResult = await this.agent.com.atproto.repo.createRecord({
|
|
3171
|
+
repo: this.repoDid,
|
|
3172
|
+
collection: HYPERCERT_COLLECTIONS.CLAIM,
|
|
3173
|
+
record: hypercertRecord,
|
|
3174
|
+
});
|
|
3175
|
+
if (!hypercertResult.success) {
|
|
3176
|
+
throw new NetworkError("Failed to create hypercert record");
|
|
3177
|
+
}
|
|
3178
|
+
const uri = hypercertResult.data.uri;
|
|
3179
|
+
const cid = hypercertResult.data.cid;
|
|
3180
|
+
this.emit("recordCreated", { uri, cid });
|
|
3181
|
+
this.emitProgress(onProgress, {
|
|
3182
|
+
name: "createHypercert",
|
|
3183
|
+
status: "success",
|
|
3184
|
+
data: { uri },
|
|
3185
|
+
});
|
|
3186
|
+
return { uri, cid };
|
|
3187
|
+
}
|
|
3188
|
+
/**
|
|
3189
|
+
* Attaches a location to a hypercert with progress tracking.
|
|
3190
|
+
*
|
|
3191
|
+
* @param hypercertUri - URI of the hypercert
|
|
3192
|
+
* @param location - Location data
|
|
3193
|
+
* @param onProgress - Optional progress callback
|
|
3194
|
+
* @returns Promise resolving to location URI
|
|
3195
|
+
* @internal
|
|
3196
|
+
*/
|
|
3197
|
+
async attachLocationWithProgress(hypercertUri, location, onProgress) {
|
|
3198
|
+
this.emitProgress(onProgress, { name: "attachLocation", status: "start" });
|
|
3199
|
+
try {
|
|
3200
|
+
const locationResult = await this.attachLocation(hypercertUri, location);
|
|
3201
|
+
this.emitProgress(onProgress, {
|
|
3202
|
+
name: "attachLocation",
|
|
3203
|
+
status: "success",
|
|
3204
|
+
data: { uri: locationResult.uri },
|
|
3205
|
+
});
|
|
3206
|
+
return locationResult.uri;
|
|
3207
|
+
}
|
|
3208
|
+
catch (error) {
|
|
3209
|
+
this.emitProgress(onProgress, { name: "attachLocation", status: "error", error: error });
|
|
3210
|
+
this.logger?.warn(`Failed to attach location: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
3211
|
+
throw error;
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
/**
|
|
3215
|
+
* Creates contribution records with progress tracking.
|
|
3216
|
+
*
|
|
3217
|
+
* @param hypercertUri - URI of the hypercert
|
|
3218
|
+
* @param contributions - Array of contribution data
|
|
3219
|
+
* @param onProgress - Optional progress callback
|
|
3220
|
+
* @returns Promise resolving to array of contribution URIs
|
|
3221
|
+
* @internal
|
|
3222
|
+
*/
|
|
3223
|
+
async createContributionsWithProgress(hypercertUri, contributions, onProgress) {
|
|
3224
|
+
this.emitProgress(onProgress, { name: "createContributions", status: "start" });
|
|
3225
|
+
try {
|
|
3226
|
+
const contributionUris = [];
|
|
3227
|
+
for (const contrib of contributions) {
|
|
3228
|
+
const contribResult = await this.addContribution({
|
|
3229
|
+
hypercertUri,
|
|
3230
|
+
contributors: contrib.contributors,
|
|
3231
|
+
role: contrib.role,
|
|
3232
|
+
description: contrib.description,
|
|
3233
|
+
});
|
|
3234
|
+
contributionUris.push(contribResult.uri);
|
|
3235
|
+
}
|
|
3236
|
+
this.emitProgress(onProgress, {
|
|
3237
|
+
name: "createContributions",
|
|
3238
|
+
status: "success",
|
|
3239
|
+
data: { count: contributionUris.length },
|
|
3240
|
+
});
|
|
3241
|
+
return contributionUris;
|
|
3242
|
+
}
|
|
3243
|
+
catch (error) {
|
|
3244
|
+
this.emitProgress(onProgress, { name: "createContributions", status: "error", error: error });
|
|
3245
|
+
this.logger?.warn(`Failed to create contributions: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
3246
|
+
throw error;
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3220
3249
|
/**
|
|
3221
3250
|
* Creates a new hypercert with all related records.
|
|
3222
3251
|
*
|
|
@@ -3293,142 +3322,31 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
3293
3322
|
};
|
|
3294
3323
|
try {
|
|
3295
3324
|
// Step 1: Upload image if provided
|
|
3296
|
-
|
|
3297
|
-
if (params.image) {
|
|
3298
|
-
this.emitProgress(params.onProgress, { name: "uploadImage", status: "start" });
|
|
3299
|
-
try {
|
|
3300
|
-
const arrayBuffer = await params.image.arrayBuffer();
|
|
3301
|
-
const uint8Array = new Uint8Array(arrayBuffer);
|
|
3302
|
-
const uploadResult = await this.agent.com.atproto.repo.uploadBlob(uint8Array, {
|
|
3303
|
-
encoding: params.image.type || "image/jpeg",
|
|
3304
|
-
});
|
|
3305
|
-
if (uploadResult.success) {
|
|
3306
|
-
imageBlobRef = {
|
|
3307
|
-
$type: "blob",
|
|
3308
|
-
ref: { $link: uploadResult.data.blob.ref.toString() },
|
|
3309
|
-
mimeType: uploadResult.data.blob.mimeType,
|
|
3310
|
-
size: uploadResult.data.blob.size,
|
|
3311
|
-
};
|
|
3312
|
-
}
|
|
3313
|
-
this.emitProgress(params.onProgress, {
|
|
3314
|
-
name: "uploadImage",
|
|
3315
|
-
status: "success",
|
|
3316
|
-
data: { size: params.image.size },
|
|
3317
|
-
});
|
|
3318
|
-
}
|
|
3319
|
-
catch (error) {
|
|
3320
|
-
this.emitProgress(params.onProgress, { name: "uploadImage", status: "error", error: error });
|
|
3321
|
-
throw new NetworkError(`Failed to upload image: ${error instanceof Error ? error.message : "Unknown"}`, error);
|
|
3322
|
-
}
|
|
3323
|
-
}
|
|
3325
|
+
const imageBlobRef = params.image ? await this.uploadImageBlob(params.image, params.onProgress) : undefined;
|
|
3324
3326
|
// Step 2: Create rights record
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
rightsName: params.rights.name,
|
|
3329
|
-
rightsType: params.rights.type,
|
|
3330
|
-
rightsDescription: params.rights.description,
|
|
3331
|
-
createdAt,
|
|
3332
|
-
};
|
|
3333
|
-
const rightsValidation = this.lexiconRegistry.validate(HYPERCERT_COLLECTIONS.RIGHTS, rightsRecord);
|
|
3334
|
-
if (!rightsValidation.valid) {
|
|
3335
|
-
throw new ValidationError(`Invalid rights record: ${rightsValidation.error}`);
|
|
3336
|
-
}
|
|
3337
|
-
const rightsResult = await this.agent.com.atproto.repo.createRecord({
|
|
3338
|
-
repo: this.repoDid,
|
|
3339
|
-
collection: HYPERCERT_COLLECTIONS.RIGHTS,
|
|
3340
|
-
record: rightsRecord,
|
|
3341
|
-
});
|
|
3342
|
-
if (!rightsResult.success) {
|
|
3343
|
-
throw new NetworkError("Failed to create rights record");
|
|
3344
|
-
}
|
|
3345
|
-
result.rightsUri = rightsResult.data.uri;
|
|
3346
|
-
result.rightsCid = rightsResult.data.cid;
|
|
3347
|
-
this.emit("rightsCreated", { uri: result.rightsUri, cid: result.rightsCid });
|
|
3348
|
-
this.emitProgress(params.onProgress, {
|
|
3349
|
-
name: "createRights",
|
|
3350
|
-
status: "success",
|
|
3351
|
-
data: { uri: result.rightsUri },
|
|
3352
|
-
});
|
|
3327
|
+
const { uri: rightsUri, cid: rightsCid } = await this.createRightsRecord(params.rights, createdAt, params.onProgress);
|
|
3328
|
+
result.rightsUri = rightsUri;
|
|
3329
|
+
result.rightsCid = rightsCid;
|
|
3353
3330
|
// Step 3: Create hypercert record
|
|
3354
|
-
this.
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
title: params.title,
|
|
3358
|
-
shortDescription: params.shortDescription,
|
|
3359
|
-
description: params.description,
|
|
3360
|
-
workScope: params.workScope,
|
|
3361
|
-
workTimeFrameFrom: params.workTimeFrameFrom,
|
|
3362
|
-
workTimeFrameTo: params.workTimeFrameTo,
|
|
3363
|
-
rights: { uri: result.rightsUri, cid: result.rightsCid },
|
|
3364
|
-
createdAt,
|
|
3365
|
-
};
|
|
3366
|
-
if (imageBlobRef) {
|
|
3367
|
-
hypercertRecord.image = imageBlobRef;
|
|
3368
|
-
}
|
|
3369
|
-
if (params.evidence && params.evidence.length > 0) {
|
|
3370
|
-
hypercertRecord.evidence = params.evidence;
|
|
3371
|
-
}
|
|
3372
|
-
const hypercertValidation = this.lexiconRegistry.validate(HYPERCERT_COLLECTIONS.CLAIM, hypercertRecord);
|
|
3373
|
-
if (!hypercertValidation.valid) {
|
|
3374
|
-
throw new ValidationError(`Invalid hypercert record: ${hypercertValidation.error}`);
|
|
3375
|
-
}
|
|
3376
|
-
const hypercertResult = await this.agent.com.atproto.repo.createRecord({
|
|
3377
|
-
repo: this.repoDid,
|
|
3378
|
-
collection: HYPERCERT_COLLECTIONS.CLAIM,
|
|
3379
|
-
record: hypercertRecord,
|
|
3380
|
-
});
|
|
3381
|
-
if (!hypercertResult.success) {
|
|
3382
|
-
throw new NetworkError("Failed to create hypercert record");
|
|
3383
|
-
}
|
|
3384
|
-
result.hypercertUri = hypercertResult.data.uri;
|
|
3385
|
-
result.hypercertCid = hypercertResult.data.cid;
|
|
3386
|
-
this.emit("recordCreated", { uri: result.hypercertUri, cid: result.hypercertCid });
|
|
3387
|
-
this.emitProgress(params.onProgress, {
|
|
3388
|
-
name: "createHypercert",
|
|
3389
|
-
status: "success",
|
|
3390
|
-
data: { uri: result.hypercertUri },
|
|
3391
|
-
});
|
|
3331
|
+
const { uri: hypercertUri, cid: hypercertCid } = await this.createHypercertRecord(params, rightsUri, rightsCid, imageBlobRef, createdAt, params.onProgress);
|
|
3332
|
+
result.hypercertUri = hypercertUri;
|
|
3333
|
+
result.hypercertCid = hypercertCid;
|
|
3392
3334
|
// Step 4: Attach location if provided
|
|
3393
3335
|
if (params.location) {
|
|
3394
|
-
this.emitProgress(params.onProgress, { name: "attachLocation", status: "start" });
|
|
3395
3336
|
try {
|
|
3396
|
-
|
|
3397
|
-
result.locationUri = locationResult.uri;
|
|
3398
|
-
this.emitProgress(params.onProgress, {
|
|
3399
|
-
name: "attachLocation",
|
|
3400
|
-
status: "success",
|
|
3401
|
-
data: { uri: result.locationUri },
|
|
3402
|
-
});
|
|
3337
|
+
result.locationUri = await this.attachLocationWithProgress(hypercertUri, params.location, params.onProgress);
|
|
3403
3338
|
}
|
|
3404
|
-
catch
|
|
3405
|
-
|
|
3406
|
-
this.logger?.warn(`Failed to attach location: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
3339
|
+
catch {
|
|
3340
|
+
// Error already logged and progress emitted
|
|
3407
3341
|
}
|
|
3408
3342
|
}
|
|
3409
3343
|
// Step 5: Create contributions if provided
|
|
3410
3344
|
if (params.contributions && params.contributions.length > 0) {
|
|
3411
|
-
this.emitProgress(params.onProgress, { name: "createContributions", status: "start" });
|
|
3412
|
-
result.contributionUris = [];
|
|
3413
3345
|
try {
|
|
3414
|
-
|
|
3415
|
-
const contribResult = await this.addContribution({
|
|
3416
|
-
hypercertUri: result.hypercertUri,
|
|
3417
|
-
contributors: contrib.contributors,
|
|
3418
|
-
role: contrib.role,
|
|
3419
|
-
description: contrib.description,
|
|
3420
|
-
});
|
|
3421
|
-
result.contributionUris.push(contribResult.uri);
|
|
3422
|
-
}
|
|
3423
|
-
this.emitProgress(params.onProgress, {
|
|
3424
|
-
name: "createContributions",
|
|
3425
|
-
status: "success",
|
|
3426
|
-
data: { count: result.contributionUris.length },
|
|
3427
|
-
});
|
|
3346
|
+
result.contributionUris = await this.createContributionsWithProgress(hypercertUri, params.contributions, params.onProgress);
|
|
3428
3347
|
}
|
|
3429
|
-
catch
|
|
3430
|
-
|
|
3431
|
-
this.logger?.warn(`Failed to create contributions: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
3348
|
+
catch {
|
|
3349
|
+
// Error already logged and progress emitted
|
|
3432
3350
|
}
|
|
3433
3351
|
}
|
|
3434
3352
|
return result;
|
|
@@ -3530,9 +3448,9 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
3530
3448
|
// Preserve existing image
|
|
3531
3449
|
recordForUpdate.image = existingRecord.image;
|
|
3532
3450
|
}
|
|
3533
|
-
const validation =
|
|
3534
|
-
if (!validation.
|
|
3535
|
-
throw new ValidationError(`Invalid hypercert record: ${validation.error}`);
|
|
3451
|
+
const validation = validate(recordForUpdate, collection, "main", false);
|
|
3452
|
+
if (!validation.success) {
|
|
3453
|
+
throw new ValidationError(`Invalid hypercert record: ${validation.error?.message}`);
|
|
3536
3454
|
}
|
|
3537
3455
|
const result = await this.agent.com.atproto.repo.putRecord({
|
|
3538
3456
|
repo: this.repoDid,
|
|
@@ -3581,10 +3499,10 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
3581
3499
|
if (!result.success) {
|
|
3582
3500
|
throw new NetworkError("Failed to get hypercert");
|
|
3583
3501
|
}
|
|
3584
|
-
// Validate with lexicon
|
|
3585
|
-
const validation =
|
|
3586
|
-
if (!validation.
|
|
3587
|
-
throw new ValidationError(`Invalid hypercert record format: ${validation.error}`);
|
|
3502
|
+
// Validate with lexicon (more lenient - doesn't require $type)
|
|
3503
|
+
const validation = validate(result.data.value, HYPERCERT_COLLECTIONS.CLAIM, "main", false);
|
|
3504
|
+
if (!validation.success) {
|
|
3505
|
+
throw new ValidationError(`Invalid hypercert record format: ${validation.error?.message}`);
|
|
3588
3506
|
}
|
|
3589
3507
|
return {
|
|
3590
3508
|
uri: result.data.uri,
|
|
@@ -3767,9 +3685,9 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
3767
3685
|
name: location.name,
|
|
3768
3686
|
description: location.description,
|
|
3769
3687
|
};
|
|
3770
|
-
const validation =
|
|
3771
|
-
if (!validation.
|
|
3772
|
-
throw new ValidationError(`Invalid location record: ${validation.error}`);
|
|
3688
|
+
const validation = validate(locationRecord, HYPERCERT_COLLECTIONS.LOCATION, "main", false);
|
|
3689
|
+
if (!validation.success) {
|
|
3690
|
+
throw new ValidationError(`Invalid location record: ${validation.error?.message}`);
|
|
3773
3691
|
}
|
|
3774
3692
|
const result = await this.agent.com.atproto.repo.createRecord({
|
|
3775
3693
|
repo: this.repoDid,
|
|
@@ -3863,9 +3781,9 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
3863
3781
|
const hypercert = await this.get(params.hypercertUri);
|
|
3864
3782
|
contributionRecord.hypercert = { uri: hypercert.uri, cid: hypercert.cid };
|
|
3865
3783
|
}
|
|
3866
|
-
const validation =
|
|
3867
|
-
if (!validation.
|
|
3868
|
-
throw new ValidationError(`Invalid contribution record: ${validation.error}`);
|
|
3784
|
+
const validation = validate(contributionRecord, HYPERCERT_COLLECTIONS.CONTRIBUTION, "main", false);
|
|
3785
|
+
if (!validation.success) {
|
|
3786
|
+
throw new ValidationError(`Invalid contribution record: ${validation.error?.message}`);
|
|
3869
3787
|
}
|
|
3870
3788
|
const result = await this.agent.com.atproto.repo.createRecord({
|
|
3871
3789
|
repo: this.repoDid,
|
|
@@ -3927,9 +3845,9 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
3927
3845
|
measurementMethodURI: params.methodUri,
|
|
3928
3846
|
evidenceURI: params.evidenceUris,
|
|
3929
3847
|
};
|
|
3930
|
-
const validation =
|
|
3931
|
-
if (!validation.
|
|
3932
|
-
throw new ValidationError(`Invalid measurement record: ${validation.error}`);
|
|
3848
|
+
const validation = validate(measurementRecord, HYPERCERT_COLLECTIONS.MEASUREMENT, "main", false);
|
|
3849
|
+
if (!validation.success) {
|
|
3850
|
+
throw new ValidationError(`Invalid measurement record: ${validation.error?.message}`);
|
|
3933
3851
|
}
|
|
3934
3852
|
const result = await this.agent.com.atproto.repo.createRecord({
|
|
3935
3853
|
repo: this.repoDid,
|
|
@@ -3980,9 +3898,9 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
3980
3898
|
summary: params.summary,
|
|
3981
3899
|
createdAt,
|
|
3982
3900
|
};
|
|
3983
|
-
const validation =
|
|
3984
|
-
if (!validation.
|
|
3985
|
-
throw new ValidationError(`Invalid evaluation record: ${validation.error}`);
|
|
3901
|
+
const validation = validate(evaluationRecord, HYPERCERT_COLLECTIONS.EVALUATION, "main", false);
|
|
3902
|
+
if (!validation.success) {
|
|
3903
|
+
throw new ValidationError(`Invalid evaluation record: ${validation.error?.message}`);
|
|
3986
3904
|
}
|
|
3987
3905
|
const result = await this.agent.com.atproto.repo.createRecord({
|
|
3988
3906
|
repo: this.repoDid,
|
|
@@ -4060,9 +3978,9 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
4060
3978
|
if (coverPhotoRef) {
|
|
4061
3979
|
collectionRecord.coverPhoto = coverPhotoRef;
|
|
4062
3980
|
}
|
|
4063
|
-
const validation =
|
|
4064
|
-
if (!validation.
|
|
4065
|
-
throw new ValidationError(`Invalid collection record: ${validation.error}`);
|
|
3981
|
+
const validation = validate(collectionRecord, HYPERCERT_COLLECTIONS.COLLECTION, "main", false);
|
|
3982
|
+
if (!validation.success) {
|
|
3983
|
+
throw new ValidationError(`Invalid collection record: ${validation.error?.message}`);
|
|
4066
3984
|
}
|
|
4067
3985
|
const result = await this.agent.com.atproto.repo.createRecord({
|
|
4068
3986
|
repo: this.repoDid,
|
|
@@ -4112,9 +4030,9 @@ class HypercertOperationsImpl extends EventEmitter {
|
|
|
4112
4030
|
throw new NetworkError("Failed to get collection");
|
|
4113
4031
|
}
|
|
4114
4032
|
// Validate with lexicon registry (more lenient - doesn't require $type)
|
|
4115
|
-
const validation =
|
|
4116
|
-
if (!validation.
|
|
4117
|
-
throw new ValidationError(`Invalid collection record format: ${validation.error}`);
|
|
4033
|
+
const validation = validate(result.data.value, HYPERCERT_COLLECTIONS.COLLECTION, "#main", false);
|
|
4034
|
+
if (!validation.success) {
|
|
4035
|
+
throw new ValidationError(`Invalid collection record format: ${validation.error?.message}`);
|
|
4118
4036
|
}
|
|
4119
4037
|
return {
|
|
4120
4038
|
uri: result.data.uri,
|
|
@@ -4911,7 +4829,6 @@ class Repository {
|
|
|
4911
4829
|
* @param session - Authenticated OAuth session
|
|
4912
4830
|
* @param serverUrl - Base URL of the AT Protocol server
|
|
4913
4831
|
* @param repoDid - DID of the repository to operate on
|
|
4914
|
-
* @param lexiconRegistry - Registry for lexicon validation
|
|
4915
4832
|
* @param isSDS - Whether this is a Shared Data Server
|
|
4916
4833
|
* @param logger - Optional logger for debugging
|
|
4917
4834
|
*
|
|
@@ -4921,20 +4838,16 @@ class Repository {
|
|
|
4921
4838
|
*
|
|
4922
4839
|
* @internal
|
|
4923
4840
|
*/
|
|
4924
|
-
constructor(session, serverUrl, repoDid,
|
|
4841
|
+
constructor(session, serverUrl, repoDid, isSDS, logger) {
|
|
4925
4842
|
this.session = session;
|
|
4926
4843
|
this.serverUrl = serverUrl;
|
|
4927
4844
|
this.repoDid = repoDid;
|
|
4928
|
-
this.lexiconRegistry = lexiconRegistry;
|
|
4929
4845
|
this._isSDS = isSDS;
|
|
4930
4846
|
this.logger = logger;
|
|
4931
4847
|
// Create a ConfigurableAgent that routes requests to the specified server URL
|
|
4932
4848
|
// This allows routing to PDS, SDS, or any custom server while maintaining
|
|
4933
4849
|
// the OAuth session's authentication
|
|
4934
4850
|
this.agent = new ConfigurableAgent(session, serverUrl);
|
|
4935
|
-
this.lexiconRegistry.addToAgent(this.agent);
|
|
4936
|
-
// Register hypercert lexicons
|
|
4937
|
-
this.lexiconRegistry.registerMany(HYPERCERT_LEXICONS);
|
|
4938
4851
|
}
|
|
4939
4852
|
/**
|
|
4940
4853
|
* The DID (Decentralized Identifier) of this repository.
|
|
@@ -5005,7 +4918,7 @@ class Repository {
|
|
|
5005
4918
|
* ```
|
|
5006
4919
|
*/
|
|
5007
4920
|
repo(did) {
|
|
5008
|
-
return new Repository(this.session, this.serverUrl, did, this.
|
|
4921
|
+
return new Repository(this.session, this.serverUrl, did, this._isSDS, this.logger);
|
|
5009
4922
|
}
|
|
5010
4923
|
/**
|
|
5011
4924
|
* Low-level record operations for CRUD on any AT Protocol record type.
|
|
@@ -5038,7 +4951,7 @@ class Repository {
|
|
|
5038
4951
|
*/
|
|
5039
4952
|
get records() {
|
|
5040
4953
|
if (!this._records) {
|
|
5041
|
-
this._records = new RecordOperationsImpl(this.agent, this.repoDid
|
|
4954
|
+
this._records = new RecordOperationsImpl(this.agent, this.repoDid);
|
|
5042
4955
|
}
|
|
5043
4956
|
return this._records;
|
|
5044
4957
|
}
|
|
@@ -5133,7 +5046,7 @@ class Repository {
|
|
|
5133
5046
|
*/
|
|
5134
5047
|
get hypercerts() {
|
|
5135
5048
|
if (!this._hypercerts) {
|
|
5136
|
-
this._hypercerts = new HypercertOperationsImpl(this.agent, this.repoDid, this.serverUrl, this.
|
|
5049
|
+
this._hypercerts = new HypercertOperationsImpl(this.agent, this.repoDid, this.serverUrl, this.logger);
|
|
5137
5050
|
}
|
|
5138
5051
|
return this._hypercerts;
|
|
5139
5052
|
}
|
|
@@ -5429,8 +5342,6 @@ class ATProtoSDK {
|
|
|
5429
5342
|
this.logger = config.logger;
|
|
5430
5343
|
// Initialize OAuth client
|
|
5431
5344
|
this.oauthClient = new OAuthClient(configWithDefaults);
|
|
5432
|
-
// Initialize lexicon registry
|
|
5433
|
-
this.lexiconRegistry = new LexiconRegistry();
|
|
5434
5345
|
this.logger?.info("ATProto SDK initialized");
|
|
5435
5346
|
}
|
|
5436
5347
|
/**
|
|
@@ -5712,30 +5623,7 @@ class ATProtoSDK {
|
|
|
5712
5623
|
}
|
|
5713
5624
|
// Get repository DID (default to session DID)
|
|
5714
5625
|
const repoDid = session.did || session.sub;
|
|
5715
|
-
return new Repository(session, serverUrl, repoDid,
|
|
5716
|
-
}
|
|
5717
|
-
/**
|
|
5718
|
-
* Gets the lexicon registry for schema validation.
|
|
5719
|
-
*
|
|
5720
|
-
* The lexicon registry manages AT Protocol lexicon schemas used for
|
|
5721
|
-
* validating record data. You can register custom lexicons to extend
|
|
5722
|
-
* the SDK's capabilities.
|
|
5723
|
-
*
|
|
5724
|
-
* @returns The {@link LexiconRegistry} instance
|
|
5725
|
-
*
|
|
5726
|
-
* @example
|
|
5727
|
-
* ```typescript
|
|
5728
|
-
* const registry = sdk.getLexiconRegistry();
|
|
5729
|
-
*
|
|
5730
|
-
* // Register custom lexicons
|
|
5731
|
-
* registry.register(myCustomLexicons);
|
|
5732
|
-
*
|
|
5733
|
-
* // Check if a lexicon is registered
|
|
5734
|
-
* const hasLexicon = registry.has("org.example.myRecord");
|
|
5735
|
-
* ```
|
|
5736
|
-
*/
|
|
5737
|
-
getLexiconRegistry() {
|
|
5738
|
-
return this.lexiconRegistry;
|
|
5626
|
+
return new Repository(session, serverUrl, repoDid, isSDS, this.logger);
|
|
5739
5627
|
}
|
|
5740
5628
|
/**
|
|
5741
5629
|
* The configured PDS (Personal Data Server) URL.
|
|
@@ -5891,5 +5779,5 @@ const CollaboratorSchema = z.object({
|
|
|
5891
5779
|
revokedAt: z.string().optional(),
|
|
5892
5780
|
});
|
|
5893
5781
|
|
|
5894
|
-
export { ATPROTO_SCOPE, ATProtoSDK, ATProtoSDKConfigSchema, ATProtoSDKError, AccountActionSchema, AccountAttrSchema, AccountPermissionSchema, AuthenticationError, BlobPermissionSchema, CollaboratorPermissionsSchema, CollaboratorSchema, ConfigurableAgent, IdentityAttrSchema, IdentityPermissionSchema, InMemorySessionStore, InMemoryStateStore, IncludePermissionSchema,
|
|
5782
|
+
export { ATPROTO_SCOPE, ATProtoSDK, ATProtoSDKConfigSchema, ATProtoSDKError, AccountActionSchema, AccountAttrSchema, AccountPermissionSchema, AuthenticationError, BlobPermissionSchema, CollaboratorPermissionsSchema, CollaboratorSchema, ConfigurableAgent, HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS, IdentityAttrSchema, IdentityPermissionSchema, InMemorySessionStore, InMemoryStateStore, IncludePermissionSchema, MimeTypeSchema, NetworkError, NsidSchema, OAuthConfigSchema, OrganizationSchema, PermissionBuilder, PermissionSchema, RepoActionSchema, RepoPermissionSchema, Repository, RpcPermissionSchema, SDSRequiredError, ScopePresets, ServerConfigSchema, SessionExpiredError, TRANSITION_SCOPES, TimeoutConfigSchema, TransitionScopeSchema, ValidationError, buildScope, createATProtoSDK, hasAllPermissions, hasAnyPermission, hasPermission, mergeScopes, parseScope, removePermissions, validateScope };
|
|
5895
5783
|
//# sourceMappingURL=index.mjs.map
|