Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/fix-lexicon-fields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@hypercerts-org/sdk-core": patch
"@hypercerts-org/sdk-react": patch
---

fix(lexicon): correct field names and types to match lexicon schema

- Fix `workTimeframeFrom/To` -> `workTimeFrameFrom/To` (capital 'F' in Frame)
- Make `shortDescription` required for hypercert claims per lexicon schema
- Update all interfaces, implementations, and tests to use correct field names
- Add comprehensive lexicon documentation to README
2 changes: 1 addition & 1 deletion packages/lexicon/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hypercerts-org/lexicon",
"version": "0.7.0",
"version": "0.8.0",
"description": "ATProto lexicon definitions and TypeScript types for the Hypercerts protocol",
"type": "module",
"main": "dist/index.cjs",
Expand Down
133 changes: 125 additions & 8 deletions packages/sdk-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,15 @@ const session = await sdk.callback(callbackParams);
const repo = sdk.getRepository(session);
const claim = await repo.hypercerts.create({
title: "Tree Planting Initiative 2025",
description: "Planted 1000 trees in the rainforest",
impact: {
scope: ["Environmental Conservation"],
work: { from: "2025-01-01", to: "2025-12-31" },
contributors: ["did:plc:contributor1"],
shortDescription: "1000 trees planted in rainforest",
description: "Planted 1000 trees in the Amazon rainforest region",
workScope: "Environmental Conservation",
workTimeFrameFrom: "2025-01-01T00:00:00Z",
workTimeFrameTo: "2025-12-31T23:59:59Z",
rights: {
name: "Attribution",
type: "license",
description: "CC-BY-4.0",
},
});
```
Expand Down Expand Up @@ -607,21 +611,134 @@ await mockStore.set(mockSession);

### Working with Lexicons

The SDK exports lexicon types and validation utilities from the `@hypercerts-org/lexicon` package for direct record manipulation and validation.

#### Lexicon Types

All lexicon types are available with proper TypeScript support:

```typescript
import type {
HypercertClaim,
HypercertRights,
HypercertContribution,
HypercertCollection,
HypercertMeasurement,
HypercertEvaluation,
HypercertLocation,
StrongRef,
} from "@hypercerts-org/sdk-core";

// Create a properly typed hypercert claim
const claim: HypercertClaim = {
$type: "org.hypercerts.claim",
title: "Community Garden Project",
shortDescription: "Urban garden serving 50 families", // REQUIRED
description: "Detailed description...",
workScope: "Food Security",
workTimeFrameFrom: "2024-01-01T00:00:00Z", // Note: Capital 'F'
workTimeFrameTo: "2024-12-31T00:00:00Z", // Note: Capital 'F'
rights: { uri: "at://...", cid: "..." },
createdAt: new Date().toISOString(),
};
```

#### Validation

Validate records before creating them:

```typescript
import {
validate,
OrgHypercertsClaim,
HYPERCERT_COLLECTIONS,
} from "@hypercerts-org/sdk-core";

// Validate using the lexicon package
const validation = validate(
HYPERCERT_COLLECTIONS.CLAIM, // "org.hypercerts.claim"
claim
);

if (!validation.valid) {
console.error("Validation failed:", validation.error);
}

// Or use type-specific validators
const isValid = OrgHypercertsClaim.isMain(claim);
const validationResult = OrgHypercertsClaim.validateMain(claim);
```

#### Using LexiconRegistry

For repository-level validation:

```typescript
import {
LexiconRegistry,
HYPERCERT_LEXICONS,
HYPERCERT_COLLECTIONS,
} from "@hypercerts-org/sdk-core/lexicons";
} from "@hypercerts-org/sdk-core";

const registry = new LexiconRegistry();
registry.registerLexicons(HYPERCERT_LEXICONS);

// Validate a record
const isValid = registry.validate(
"org.hypercerts.claim",
const result = registry.validate(
HYPERCERT_COLLECTIONS.CLAIM,
claimData
);

if (!result.valid) {
console.error("Invalid record:", result.error);
}
```

#### Creating Records with Proper Types

```typescript
import type {
HypercertContribution,
StrongRef,
} from "@hypercerts-org/sdk-core";
import { HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";

// Create a contribution record
const contribution: HypercertContribution = {
$type: HYPERCERT_COLLECTIONS.CONTRIBUTION,
hypercert: {
uri: "at://did:plc:abc/org.hypercerts.claim/xyz",
cid: "bafyrei...",
} as StrongRef,
contributors: ["did:plc:contributor1", "did:plc:contributor2"],
role: "implementer",
description: "On-ground implementation team",
workTimeframeFrom: "2024-01-01T00:00:00Z", // Note: lowercase 'f' for contributions
workTimeframeTo: "2024-06-30T00:00:00Z", // Note: lowercase 'f' for contributions
createdAt: new Date().toISOString(),
};

// Use with repository operations
await repo.records.create({
collection: HYPERCERT_COLLECTIONS.CONTRIBUTION,
record: contribution,
});
```

#### Available Lexicon Collections

```typescript
import { HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";

// Collection NSIDs
HYPERCERT_COLLECTIONS.CLAIM // "org.hypercerts.claim"
HYPERCERT_COLLECTIONS.RIGHTS // "org.hypercerts.claim.rights"
HYPERCERT_COLLECTIONS.CONTRIBUTION // "org.hypercerts.claim.contribution"
HYPERCERT_COLLECTIONS.MEASUREMENT // "org.hypercerts.claim.measurement"
HYPERCERT_COLLECTIONS.EVALUATION // "org.hypercerts.claim.evaluation"
HYPERCERT_COLLECTIONS.EVIDENCE // "org.hypercerts.claim.evidence"
HYPERCERT_COLLECTIONS.COLLECTION // "org.hypercerts.collection"
HYPERCERT_COLLECTIONS.LOCATION // "app.certified.location"
```

## Development
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hypercerts-org/sdk-core",
"version": "0.7.0",
"version": "0.8.0",
"description": "Framework-agnostic ATProto SDK core for authentication, repository operations, and lexicon management",
"main": "dist/index.cjs",
"repository": {
Expand Down
9 changes: 3 additions & 6 deletions packages/sdk-core/src/repository/HypercertOperationsImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,18 +266,15 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
const hypercertRecord: Record<string, unknown> = {
$type: HYPERCERT_COLLECTIONS.CLAIM,
title: params.title,
shortDescription: params.shortDescription,
description: params.description,
workScope: params.workScope,
workTimeframeFrom: params.workTimeframeFrom,
workTimeframeTo: params.workTimeframeTo,
workTimeFrameFrom: params.workTimeFrameFrom,
workTimeFrameTo: params.workTimeFrameTo,
rights: { uri: result.rightsUri, cid: result.rightsCid },
createdAt,
};

if (params.shortDescription) {
hypercertRecord.shortDescription = params.shortDescription;
}

if (imageBlobRef) {
hypercertRecord.image = imageBlobRef;
}
Expand Down
10 changes: 5 additions & 5 deletions packages/sdk-core/src/repository/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@ export interface CreateHypercertParams {
*
* ISO 8601 date format (YYYY-MM-DD).
*/
workTimeframeFrom: string;
workTimeFrameFrom: string;

/**
* End date of the work period.
*
* ISO 8601 date format (YYYY-MM-DD).
*/
workTimeframeTo: string;
workTimeFrameTo: string;

/**
* Rights associated with the hypercert.
Expand Down Expand Up @@ -153,11 +153,11 @@ export interface CreateHypercertParams {
};

/**
* Optional short description for display in lists/cards.
* Short description for display in lists/cards.
*
* Should be under 200 characters.
* Required field. Should be under 300 characters.
*/
shortDescription?: string;
shortDescription: string;

/**
* Optional cover image for the hypercert.
Expand Down
33 changes: 17 additions & 16 deletions packages/sdk-core/tests/repository/HypercertOperationsImpl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ describe("HypercertOperationsImpl", () => {
describe("create", () => {
const validParams = {
title: "Test Hypercert",
shortDescription: "A test hypercert",
description: "A test hypercert for unit testing",
workScope: "Testing",
workTimeframeFrom: "2024-01-01T00:00:00Z",
workTimeframeTo: "2024-12-31T23:59:59Z",
workTimeFrameFrom: "2024-01-01T00:00:00Z",
workTimeFrameTo: "2024-12-31T23:59:59Z",
rights: {
name: "Attribution",
type: "CC-BY-4.0",
Expand Down Expand Up @@ -138,8 +139,8 @@ describe("HypercertOperationsImpl", () => {
title: "Test",
description: "Test",
workScope: "Test",
workTimeframeFrom: "2024-01-01",
workTimeframeTo: "2024-12-31",
workTimeFrameFrom: "2024-01-01",
workTimeFrameTo: "2024-12-31",
createdAt: "2024-01-01",
},
},
Expand Down Expand Up @@ -178,8 +179,8 @@ describe("HypercertOperationsImpl", () => {
title: "Test",
description: "Test",
workScope: "Test",
workTimeframeFrom: "2024-01-01",
workTimeframeTo: "2024-12-31",
workTimeFrameFrom: "2024-01-01",
workTimeFrameTo: "2024-12-31",
createdAt: "2024-01-01",
},
},
Expand Down Expand Up @@ -337,8 +338,8 @@ describe("HypercertOperationsImpl", () => {
title: "Old Title",
description: "Old description",
workScope: "Old scope",
workTimeframeFrom: "2024-01-01",
workTimeframeTo: "2024-12-31",
workTimeFrameFrom: "2024-01-01",
workTimeFrameTo: "2024-12-31",
createdAt: "2024-01-01T00:00:00Z",
rights: { uri: "at://rights", cid: "rights-cid" },
},
Expand Down Expand Up @@ -403,8 +404,8 @@ describe("HypercertOperationsImpl", () => {
title: "Title",
description: "Desc",
workScope: "Scope",
workTimeframeFrom: "2024-01-01",
workTimeframeTo: "2024-12-31",
workTimeFrameFrom: "2024-01-01",
workTimeFrameTo: "2024-12-31",
createdAt: "2024-01-01",
rights: { uri: "at://rights", cid: "cid" },
image: { ref: { $link: "old-image" } },
Expand Down Expand Up @@ -462,8 +463,8 @@ describe("HypercertOperationsImpl", () => {
title: "Test",
description: "Test",
workScope: "Test",
workTimeframeFrom: "2024-01-01",
workTimeframeTo: "2024-12-31",
workTimeFrameFrom: "2024-01-01",
workTimeFrameTo: "2024-12-31",
createdAt: "2024-01-01",
},
},
Expand Down Expand Up @@ -519,8 +520,8 @@ describe("HypercertOperationsImpl", () => {
title: "Test",
description: "Test",
workScope: "Test",
workTimeframeFrom: "2024-01-01",
workTimeframeTo: "2024-12-31",
workTimeFrameFrom: "2024-01-01",
workTimeFrameTo: "2024-12-31",
createdAt: "2024-01-01",
},
},
Expand Down Expand Up @@ -555,8 +556,8 @@ describe("HypercertOperationsImpl", () => {
title: "Test",
description: "Test",
workScope: "Test",
workTimeframeFrom: "2024-01-01",
workTimeframeTo: "2024-12-31",
workTimeFrameFrom: "2024-01-01",
workTimeFrameTo: "2024-12-31",
createdAt: "2024-01-01",
},
},
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hypercerts-org/sdk-react",
"version": "0.7.0",
"version": "0.8.0",
"description": "React hooks and components for the Hypercerts ATProto SDK",
"type": "module",
"main": "dist/index.cjs",
Expand Down
5 changes: 3 additions & 2 deletions packages/sdk-react/src/hooks/useHypercerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ const DEFAULT_LIMIT = 50;
* const handleSubmit = async (data) => {
* const result = await create({
* title: data.title,
* shortDescription: data.shortDesc,
* description: data.description,
* workScope: data.workScope,
* workTimeframeFrom: data.startDate,
* workTimeframeTo: data.endDate,
* workTimeFrameFrom: data.startDate,
* workTimeFrameTo: data.endDate,
* rights: {
* name: "CC-BY-4.0",
* type: "license",
Expand Down
Loading