@hypercerts-org/sdk-core 0.7.0-beta.0 → 0.9.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,11 +33,15 @@ const session = await sdk.callback(callbackParams);
33
33
  const repo = sdk.getRepository(session);
34
34
  const claim = await repo.hypercerts.create({
35
35
  title: "Tree Planting Initiative 2025",
36
- description: "Planted 1000 trees in the rainforest",
37
- impact: {
38
- scope: ["Environmental Conservation"],
39
- work: { from: "2025-01-01", to: "2025-12-31" },
40
- contributors: ["did:plc:contributor1"],
36
+ shortDescription: "1000 trees planted in rainforest",
37
+ description: "Planted 1000 trees in the Amazon rainforest region",
38
+ workScope: "Environmental Conservation",
39
+ workTimeFrameFrom: "2025-01-01T00:00:00Z",
40
+ workTimeFrameTo: "2025-12-31T23:59:59Z",
41
+ rights: {
42
+ name: "Attribution",
43
+ type: "license",
44
+ description: "CC-BY-4.0",
41
45
  },
42
46
  });
43
47
  ```
@@ -607,21 +611,134 @@ await mockStore.set(mockSession);
607
611
 
608
612
  ### Working with Lexicons
609
613
 
614
+ The SDK exports lexicon types and validation utilities from the `@hypercerts-org/lexicon` package for direct record manipulation and validation.
615
+
616
+ #### Lexicon Types
617
+
618
+ All lexicon types are available with proper TypeScript support:
619
+
620
+ ```typescript
621
+ import type {
622
+ HypercertClaim,
623
+ HypercertRights,
624
+ HypercertContribution,
625
+ HypercertCollection,
626
+ HypercertMeasurement,
627
+ HypercertEvaluation,
628
+ HypercertLocation,
629
+ StrongRef,
630
+ } from "@hypercerts-org/sdk-core";
631
+
632
+ // Create a properly typed hypercert claim
633
+ const claim: HypercertClaim = {
634
+ $type: "org.hypercerts.claim",
635
+ title: "Community Garden Project",
636
+ shortDescription: "Urban garden serving 50 families", // REQUIRED
637
+ description: "Detailed description...",
638
+ workScope: "Food Security",
639
+ workTimeFrameFrom: "2024-01-01T00:00:00Z", // Note: Capital 'F'
640
+ workTimeFrameTo: "2024-12-31T00:00:00Z", // Note: Capital 'F'
641
+ rights: { uri: "at://...", cid: "..." },
642
+ createdAt: new Date().toISOString(),
643
+ };
644
+ ```
645
+
646
+ #### Validation
647
+
648
+ Validate records before creating them:
649
+
650
+ ```typescript
651
+ import {
652
+ validate,
653
+ OrgHypercertsClaim,
654
+ HYPERCERT_COLLECTIONS,
655
+ } from "@hypercerts-org/sdk-core";
656
+
657
+ // Validate using the lexicon package
658
+ const validation = validate(
659
+ HYPERCERT_COLLECTIONS.CLAIM, // "org.hypercerts.claim"
660
+ claim
661
+ );
662
+
663
+ if (!validation.valid) {
664
+ console.error("Validation failed:", validation.error);
665
+ }
666
+
667
+ // Or use type-specific validators
668
+ const isValid = OrgHypercertsClaim.isMain(claim);
669
+ const validationResult = OrgHypercertsClaim.validateMain(claim);
670
+ ```
671
+
672
+ #### Using LexiconRegistry
673
+
674
+ For repository-level validation:
675
+
610
676
  ```typescript
611
677
  import {
612
678
  LexiconRegistry,
613
679
  HYPERCERT_LEXICONS,
614
680
  HYPERCERT_COLLECTIONS,
615
- } from "@hypercerts-org/sdk-core/lexicons";
681
+ } from "@hypercerts-org/sdk-core";
616
682
 
617
683
  const registry = new LexiconRegistry();
618
684
  registry.registerLexicons(HYPERCERT_LEXICONS);
619
685
 
620
686
  // Validate a record
621
- const isValid = registry.validate(
622
- "org.hypercerts.claim",
687
+ const result = registry.validate(
688
+ HYPERCERT_COLLECTIONS.CLAIM,
623
689
  claimData
624
690
  );
691
+
692
+ if (!result.valid) {
693
+ console.error("Invalid record:", result.error);
694
+ }
695
+ ```
696
+
697
+ #### Creating Records with Proper Types
698
+
699
+ ```typescript
700
+ import type {
701
+ HypercertContribution,
702
+ StrongRef,
703
+ } from "@hypercerts-org/sdk-core";
704
+ import { HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";
705
+
706
+ // Create a contribution record
707
+ const contribution: HypercertContribution = {
708
+ $type: HYPERCERT_COLLECTIONS.CONTRIBUTION,
709
+ hypercert: {
710
+ uri: "at://did:plc:abc/org.hypercerts.claim/xyz",
711
+ cid: "bafyrei...",
712
+ } as StrongRef,
713
+ contributors: ["did:plc:contributor1", "did:plc:contributor2"],
714
+ role: "implementer",
715
+ description: "On-ground implementation team",
716
+ workTimeframeFrom: "2024-01-01T00:00:00Z", // Note: lowercase 'f' for contributions
717
+ workTimeframeTo: "2024-06-30T00:00:00Z", // Note: lowercase 'f' for contributions
718
+ createdAt: new Date().toISOString(),
719
+ };
720
+
721
+ // Use with repository operations
722
+ await repo.records.create({
723
+ collection: HYPERCERT_COLLECTIONS.CONTRIBUTION,
724
+ record: contribution,
725
+ });
726
+ ```
727
+
728
+ #### Available Lexicon Collections
729
+
730
+ ```typescript
731
+ import { HYPERCERT_COLLECTIONS } from "@hypercerts-org/sdk-core";
732
+
733
+ // Collection NSIDs
734
+ HYPERCERT_COLLECTIONS.CLAIM // "org.hypercerts.claim"
735
+ HYPERCERT_COLLECTIONS.RIGHTS // "org.hypercerts.claim.rights"
736
+ HYPERCERT_COLLECTIONS.CONTRIBUTION // "org.hypercerts.claim.contribution"
737
+ HYPERCERT_COLLECTIONS.MEASUREMENT // "org.hypercerts.claim.measurement"
738
+ HYPERCERT_COLLECTIONS.EVALUATION // "org.hypercerts.claim.evaluation"
739
+ HYPERCERT_COLLECTIONS.EVIDENCE // "org.hypercerts.claim.evidence"
740
+ HYPERCERT_COLLECTIONS.COLLECTION // "org.hypercerts.collection"
741
+ HYPERCERT_COLLECTIONS.LOCATION // "app.certified.location"
625
742
  ```
626
743
 
627
744
  ## Development
package/dist/index.cjs CHANGED
@@ -2270,6 +2270,7 @@ class HypercertOperationsImpl extends eventemitter3.EventEmitter {
2270
2270
  // Step 2: Create rights record
2271
2271
  this.emitProgress(params.onProgress, { name: "createRights", status: "start" });
2272
2272
  const rightsRecord = {
2273
+ $type: lexicon.HYPERCERT_COLLECTIONS.RIGHTS,
2273
2274
  rightsName: params.rights.name,
2274
2275
  rightsType: params.rights.type,
2275
2276
  rightsDescription: params.rights.description,
@@ -2298,17 +2299,16 @@ class HypercertOperationsImpl extends eventemitter3.EventEmitter {
2298
2299
  // Step 3: Create hypercert record
2299
2300
  this.emitProgress(params.onProgress, { name: "createHypercert", status: "start" });
2300
2301
  const hypercertRecord = {
2302
+ $type: lexicon.HYPERCERT_COLLECTIONS.CLAIM,
2301
2303
  title: params.title,
2304
+ shortDescription: params.shortDescription,
2302
2305
  description: params.description,
2303
2306
  workScope: params.workScope,
2304
- workTimeframeFrom: params.workTimeframeFrom,
2305
- workTimeframeTo: params.workTimeframeTo,
2307
+ workTimeFrameFrom: params.workTimeFrameFrom,
2308
+ workTimeFrameTo: params.workTimeFrameTo,
2306
2309
  rights: { uri: result.rightsUri, cid: result.rightsCid },
2307
2310
  createdAt,
2308
2311
  };
2309
- if (params.shortDescription) {
2310
- hypercertRecord.shortDescription = params.shortDescription;
2311
- }
2312
2312
  if (imageBlobRef) {
2313
2313
  hypercertRecord.image = imageBlobRef;
2314
2314
  }
@@ -2645,6 +2645,7 @@ class HypercertOperationsImpl extends eventemitter3.EventEmitter {
2645
2645
  * await repo.hypercerts.attachLocation(hypercertUri, {
2646
2646
  * value: "San Francisco, CA",
2647
2647
  * name: "SF Bay Area",
2648
+ * srs: "EPSG:4326",
2648
2649
  * });
2649
2650
  * ```
2650
2651
  *
@@ -2663,32 +2664,54 @@ class HypercertOperationsImpl extends eventemitter3.EventEmitter {
2663
2664
  */
2664
2665
  async attachLocation(hypercertUri, location) {
2665
2666
  try {
2666
- // Get hypercert to get CID
2667
- const hypercert = await this.get(hypercertUri);
2667
+ // Validate required srs field
2668
+ if (!location.srs) {
2669
+ throw new ValidationError("srs (Spatial Reference System) is required. Example: 'EPSG:4326' for WGS84 coordinates, or 'http://www.opengis.net/def/crs/OGC/1.3/CRS84' for CRS84.");
2670
+ }
2671
+ // Validate that hypercert exists (unused but confirms hypercert is valid)
2672
+ await this.get(hypercertUri);
2668
2673
  const createdAt = new Date().toISOString();
2669
- let locationValue = location.value;
2674
+ // Determine location type and prepare location data
2675
+ let locationData;
2676
+ let locationType;
2670
2677
  if (location.geojson) {
2678
+ // Upload GeoJSON as a blob
2671
2679
  const arrayBuffer = await location.geojson.arrayBuffer();
2672
2680
  const uint8Array = new Uint8Array(arrayBuffer);
2673
2681
  const uploadResult = await this.agent.com.atproto.repo.uploadBlob(uint8Array, {
2674
2682
  encoding: location.geojson.type || "application/geo+json",
2675
2683
  });
2676
2684
  if (uploadResult.success) {
2677
- locationValue = {
2685
+ locationData = {
2678
2686
  $type: "blob",
2679
2687
  ref: { $link: uploadResult.data.blob.ref.toString() },
2680
2688
  mimeType: uploadResult.data.blob.mimeType,
2681
2689
  size: uploadResult.data.blob.size,
2682
2690
  };
2691
+ locationType = "geojson-point";
2692
+ }
2693
+ else {
2694
+ throw new NetworkError("Failed to upload GeoJSON blob");
2683
2695
  }
2684
2696
  }
2697
+ else {
2698
+ // Use value as a URI reference
2699
+ locationData = {
2700
+ $type: "app.certified.defs#uri",
2701
+ uri: location.value,
2702
+ };
2703
+ locationType = "coordinate-decimal";
2704
+ }
2705
+ // Build location record according to app.certified.location lexicon
2685
2706
  const locationRecord = {
2686
- hypercert: { uri: hypercert.uri, cid: hypercert.cid },
2687
- value: locationValue,
2707
+ $type: lexicon.HYPERCERT_COLLECTIONS.LOCATION,
2708
+ lpVersion: "1.0",
2709
+ srs: location.srs,
2710
+ locationType,
2711
+ location: locationData,
2688
2712
  createdAt,
2689
2713
  name: location.name,
2690
2714
  description: location.description,
2691
- srs: location.srs,
2692
2715
  };
2693
2716
  const validation = this.lexiconRegistry.validate(lexicon.HYPERCERT_COLLECTIONS.LOCATION, locationRecord);
2694
2717
  if (!validation.valid) {
@@ -2775,10 +2798,12 @@ class HypercertOperationsImpl extends eventemitter3.EventEmitter {
2775
2798
  try {
2776
2799
  const createdAt = new Date().toISOString();
2777
2800
  const contributionRecord = {
2801
+ $type: lexicon.HYPERCERT_COLLECTIONS.CONTRIBUTION,
2778
2802
  contributors: params.contributors,
2779
2803
  role: params.role,
2780
2804
  createdAt,
2781
2805
  description: params.description,
2806
+ hypercert: { uri: "", cid: "" }, // Will be set below if hypercertUri provided
2782
2807
  };
2783
2808
  if (params.hypercertUri) {
2784
2809
  const hypercert = await this.get(params.hypercertUri);
@@ -2839,6 +2864,7 @@ class HypercertOperationsImpl extends eventemitter3.EventEmitter {
2839
2864
  const hypercert = await this.get(params.hypercertUri);
2840
2865
  const createdAt = new Date().toISOString();
2841
2866
  const measurementRecord = {
2867
+ $type: lexicon.HYPERCERT_COLLECTIONS.MEASUREMENT,
2842
2868
  hypercert: { uri: hypercert.uri, cid: hypercert.cid },
2843
2869
  measurers: params.measurers,
2844
2870
  metric: params.metric,
@@ -2894,6 +2920,7 @@ class HypercertOperationsImpl extends eventemitter3.EventEmitter {
2894
2920
  const subject = await this.get(params.subjectUri);
2895
2921
  const createdAt = new Date().toISOString();
2896
2922
  const evaluationRecord = {
2923
+ $type: lexicon.HYPERCERT_COLLECTIONS.EVALUATION,
2897
2924
  subject: { uri: subject.uri, cid: subject.cid },
2898
2925
  evaluators: params.evaluators,
2899
2926
  summary: params.summary,
@@ -2968,6 +2995,7 @@ class HypercertOperationsImpl extends eventemitter3.EventEmitter {
2968
2995
  }
2969
2996
  }
2970
2997
  const collectionRecord = {
2998
+ $type: lexicon.HYPERCERT_COLLECTIONS.COLLECTION,
2971
2999
  title: params.title,
2972
3000
  claims: params.claims.map((c) => ({ claim: { uri: c.uri, cid: c.cid }, weight: c.weight })),
2973
3001
  createdAt,