@@ -293,12 +293,20 @@ describe("HypercertOperationsImpl", () => {
293293
294294 it ( "should create contributions when provided" , async ( ) => {
295295 // Contributors are now embedded in the claim record, not created as separate records
296+ // String DIDs are converted to contributorInformation records first
296297 mockAgent . com . atproto . repo . createRecord . mockReset ( ) ;
297298 mockAgent . com . atproto . repo . createRecord
298299 . mockResolvedValueOnce ( {
299300 success : true ,
300301 data : { uri : "at://did:plc:test/org.hypercerts.claim.rights/abc" , cid : "rights-cid" } ,
301302 } )
303+ . mockResolvedValueOnce ( {
304+ success : true ,
305+ data : {
306+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
307+ cid : "contributor-cid" ,
308+ } ,
309+ } )
302310 . mockResolvedValueOnce ( {
303311 success : true ,
304312 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
@@ -311,11 +319,20 @@ describe("HypercertOperationsImpl", () => {
311319
312320 expect ( result . hypercertUri ) . toBeDefined ( ) ;
313321
314- // Verify contributors are embedded in the claim record
315- const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 1 ] [ 0 ] ;
322+ // Verify contributorInformation record was created
323+ const contributorCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 1 ] [ 0 ] ;
324+ expect ( contributorCall . collection ) . toBe ( "org.hypercerts.claim.contributorInformation" ) ;
325+ expect ( contributorCall . record . identifier ) . toBe ( "did:plc:contrib1" ) ;
326+
327+ // Verify contributors are embedded in the claim record with StrongRef (includes $type)
328+ const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 2 ] [ 0 ] ;
316329 expect ( createCall . record . contributors ) . toBeDefined ( ) ;
317330 expect ( createCall . record . contributors ) . toHaveLength ( 1 ) ;
318- expect ( createCall . record . contributors [ 0 ] . contributorIdentity ) . toBe ( "did:plc:contrib1" ) ;
331+ expect ( createCall . record . contributors [ 0 ] . contributorIdentity ) . toEqual ( {
332+ $type : "com.atproto.repo.strongRef" ,
333+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
334+ cid : "contributor-cid" ,
335+ } ) ;
319336 expect ( createCall . record . contributors [ 0 ] . contributionDetails ) . toBe ( "Developer" ) ;
320337 } ) ;
321338
@@ -330,6 +347,13 @@ describe("HypercertOperationsImpl", () => {
330347 success : true ,
331348 data : { uri : "at://did:plc:test/org.hypercerts.claim.contributionDetails/xyz" , cid : "details-cid" } ,
332349 } )
350+ . mockResolvedValueOnce ( {
351+ success : true ,
352+ data : {
353+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
354+ cid : "contributor-cid" ,
355+ } ,
356+ } )
333357 . mockResolvedValueOnce ( {
334358 success : true ,
335359 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
@@ -353,11 +377,16 @@ describe("HypercertOperationsImpl", () => {
353377 expect ( contributionCall . record . role ) . toBe ( "Developer" ) ;
354378 expect ( contributionCall . record . contributionDescription ) . toBe ( "Backend work" ) ;
355379
356- // Verify contributors use StrongRef in the claim record
357- const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 2 ] [ 0 ] ;
380+ // Verify contributors use StrongRef in the claim record (with $type for lexicon validation)
381+ const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 3 ] [ 0 ] ;
358382 expect ( createCall . record . contributors ) . toBeDefined ( ) ;
359- expect ( createCall . record . contributors [ 0 ] . contributorIdentity ) . toBe ( "did:plc:contrib1" ) ;
383+ expect ( createCall . record . contributors [ 0 ] . contributorIdentity ) . toEqual ( {
384+ $type : "com.atproto.repo.strongRef" ,
385+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
386+ cid : "contributor-cid" ,
387+ } ) ;
360388 expect ( createCall . record . contributors [ 0 ] . contributionDetails ) . toEqual ( {
389+ $type : "com.atproto.repo.strongRef" ,
361390 uri : "at://did:plc:test/org.hypercerts.claim.contributionDetails/xyz" ,
362391 cid : "details-cid" ,
363392 } ) ;
@@ -370,6 +399,13 @@ describe("HypercertOperationsImpl", () => {
370399 success : true ,
371400 data : { uri : "at://did:plc:test/org.hypercerts.claim.rights/abc" , cid : "rights-cid" } ,
372401 } )
402+ . mockResolvedValueOnce ( {
403+ success : true ,
404+ data : {
405+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
406+ cid : "contributor-cid" ,
407+ } ,
408+ } )
373409 . mockResolvedValueOnce ( {
374410 success : true ,
375411 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
@@ -380,7 +416,7 @@ describe("HypercertOperationsImpl", () => {
380416 contributions : [ { contributors : [ "did:plc:contrib1" ] , contributionDetails : "Developer" , weight : "0.75" } ] ,
381417 } ) ;
382418
383- const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 1 ] [ 0 ] ;
419+ const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 2 ] [ 0 ] ;
384420 expect ( createCall . record . contributors [ 0 ] . contributionWeight ) . toBe ( "0.75" ) ;
385421 expect ( createCall . record . contributors [ 0 ] . contributionDetails ) . toBe ( "Developer" ) ;
386422 } ) ;
@@ -392,6 +428,13 @@ describe("HypercertOperationsImpl", () => {
392428 success : true ,
393429 data : { uri : "at://did:plc:test/org.hypercerts.claim.rights/abc" , cid : "rights-cid" } ,
394430 } )
431+ . mockResolvedValueOnce ( {
432+ success : true ,
433+ data : {
434+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
435+ cid : "contributor-cid" ,
436+ } ,
437+ } )
395438 . mockResolvedValueOnce ( {
396439 success : true ,
397440 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
@@ -402,7 +445,7 @@ describe("HypercertOperationsImpl", () => {
402445 contributions : [ { contributors : [ "did:plc:contrib1" ] , contributionDetails : "Developer" } ] ,
403446 } ) ;
404447
405- const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 1 ] [ 0 ] ;
448+ const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 2 ] [ 0 ] ;
406449 expect ( createCall . record . contributors [ 0 ] . contributionWeight ) . toBeUndefined ( ) ;
407450 } ) ;
408451
@@ -417,6 +460,13 @@ describe("HypercertOperationsImpl", () => {
417460 success : true ,
418461 data : { uri : "at://did:plc:test/org.hypercerts.claim.contributionDetails/xyz" , cid : "details-cid" } ,
419462 } )
463+ . mockResolvedValueOnce ( {
464+ success : true ,
465+ data : {
466+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
467+ cid : "contributor-cid" ,
468+ } ,
469+ } )
420470 . mockResolvedValueOnce ( {
421471 success : true ,
422472 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
@@ -433,9 +483,10 @@ describe("HypercertOperationsImpl", () => {
433483 ] ,
434484 } ) ;
435485
436- const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 2 ] [ 0 ] ;
486+ const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 3 ] [ 0 ] ;
437487 expect ( createCall . record . contributors [ 0 ] . contributionWeight ) . toBe ( "1.5" ) ;
438488 expect ( createCall . record . contributors [ 0 ] . contributionDetails ) . toEqual ( {
489+ $type : "com.atproto.repo.strongRef" ,
439490 uri : "at://did:plc:test/org.hypercerts.claim.contributionDetails/xyz" ,
440491 cid : "details-cid" ,
441492 } ) ;
@@ -453,14 +504,20 @@ describe("HypercertOperationsImpl", () => {
453504 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
454505 } ) ;
455506
507+ // When a StrongRef is provided directly, no contributorInformation record is created
456508 const contributorRef = { uri : "at://did:plc:test/org.hypercerts.actor.profile/xyz" , cid : "profile-cid" } ;
457509 await hypercertOps . create ( {
458510 ...validParams ,
459511 contributions : [ { contributors : [ contributorRef ] , contributionDetails : "Developer" } ] ,
460512 } ) ;
461513
462514 const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 1 ] [ 0 ] ;
463- expect ( createCall . record . contributors [ 0 ] . contributorIdentity ) . toEqual ( contributorRef ) ;
515+ // StrongRef gets $type added for lexicon validation
516+ expect ( createCall . record . contributors [ 0 ] . contributorIdentity ) . toEqual ( {
517+ $type : "com.atproto.repo.strongRef" ,
518+ uri : "at://did:plc:test/org.hypercerts.actor.profile/xyz" ,
519+ cid : "profile-cid" ,
520+ } ) ;
464521 } ) ;
465522
466523 it ( "should support mixed string DIDs and StrongRefs for contributors" , async ( ) => {
@@ -470,21 +527,39 @@ describe("HypercertOperationsImpl", () => {
470527 success : true ,
471528 data : { uri : "at://did:plc:test/org.hypercerts.claim.rights/abc" , cid : "rights-cid" } ,
472529 } )
530+ . mockResolvedValueOnce ( {
531+ success : true ,
532+ data : {
533+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/string-did" ,
534+ cid : "string-contributor-cid" ,
535+ } ,
536+ } )
473537 . mockResolvedValueOnce ( {
474538 success : true ,
475539 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
476540 } ) ;
477541
542+ // String DID creates a contributorInformation record, StrongRef is used directly
478543 const contributorRef = { uri : "at://did:plc:test/org.hypercerts.actor.profile/xyz" , cid : "profile-cid" } ;
479544 await hypercertOps . create ( {
480545 ...validParams ,
481546 contributions : [ { contributors : [ "did:plc:string-did" , contributorRef ] , contributionDetails : "Developer" } ] ,
482547 } ) ;
483548
484- const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 1 ] [ 0 ] ;
549+ const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 2 ] [ 0 ] ;
485550 expect ( createCall . record . contributors ) . toHaveLength ( 2 ) ;
486- expect ( createCall . record . contributors [ 0 ] . contributorIdentity ) . toBe ( "did:plc:string-did" ) ;
487- expect ( createCall . record . contributors [ 1 ] . contributorIdentity ) . toEqual ( contributorRef ) ;
551+ // String DID gets converted to StrongRef pointing to contributorInformation record
552+ expect ( createCall . record . contributors [ 0 ] . contributorIdentity ) . toEqual ( {
553+ $type : "com.atproto.repo.strongRef" ,
554+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/string-did" ,
555+ cid : "string-contributor-cid" ,
556+ } ) ;
557+ // Provided StrongRef gets $type added
558+ expect ( createCall . record . contributors [ 1 ] . contributorIdentity ) . toEqual ( {
559+ $type : "com.atproto.repo.strongRef" ,
560+ uri : "at://did:plc:test/org.hypercerts.actor.profile/xyz" ,
561+ cid : "profile-cid" ,
562+ } ) ;
488563 } ) ;
489564
490565 it ( "should use contributionDetailsRef directly when provided" , async ( ) => {
@@ -494,6 +569,13 @@ describe("HypercertOperationsImpl", () => {
494569 success : true ,
495570 data : { uri : "at://did:plc:test/org.hypercerts.claim.rights/abc" , cid : "rights-cid" } ,
496571 } )
572+ . mockResolvedValueOnce ( {
573+ success : true ,
574+ data : {
575+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
576+ cid : "contributor-cid" ,
577+ } ,
578+ } )
497579 . mockResolvedValueOnce ( {
498580 success : true ,
499581 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
@@ -508,10 +590,14 @@ describe("HypercertOperationsImpl", () => {
508590 contributions : [ { contributors : [ "did:plc:contrib1" ] , contributionDetails : detailsRef } ] ,
509591 } ) ;
510592
511- // Should only create rights + hypercert, NOT contributionDetails (since ref was provided)
512- expect ( mockAgent . com . atproto . repo . createRecord ) . toHaveBeenCalledTimes ( 2 ) ;
513- const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 1 ] [ 0 ] ;
514- expect ( createCall . record . contributors [ 0 ] . contributionDetails ) . toEqual ( detailsRef ) ;
593+ // Should create rights + contributorInformation + hypercert (NOT contributionDetails since ref was provided)
594+ expect ( mockAgent . com . atproto . repo . createRecord ) . toHaveBeenCalledTimes ( 3 ) ;
595+ const createCall = mockAgent . com . atproto . repo . createRecord . mock . calls [ 2 ] [ 0 ] ;
596+ expect ( createCall . record . contributors [ 0 ] . contributionDetails ) . toEqual ( {
597+ $type : "com.atproto.repo.strongRef" ,
598+ uri : "at://did:plc:test/org.hypercerts.claim.contributionDetails/existing" ,
599+ cid : "existing-cid" ,
600+ } ) ;
515601 } ) ;
516602
517603 it ( "should pass through extra properties to contributionDetails record" , async ( ) => {
@@ -525,6 +611,13 @@ describe("HypercertOperationsImpl", () => {
525611 success : true ,
526612 data : { uri : "at://did:plc:test/org.hypercerts.claim.contributionDetails/xyz" , cid : "details-cid" } ,
527613 } )
614+ . mockResolvedValueOnce ( {
615+ success : true ,
616+ data : {
617+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
618+ cid : "contributor-cid" ,
619+ } ,
620+ } )
528621 . mockResolvedValueOnce ( {
529622 success : true ,
530623 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
@@ -561,6 +654,13 @@ describe("HypercertOperationsImpl", () => {
561654 success : true ,
562655 data : { uri : "at://did:plc:test/org.hypercerts.claim.contributionDetails/xyz" , cid : "details-cid" } ,
563656 } )
657+ . mockResolvedValueOnce ( {
658+ success : true ,
659+ data : {
660+ uri : "at://did:plc:test/org.hypercerts.claim.contributorInformation/contrib1" ,
661+ cid : "contributor-cid" ,
662+ } ,
663+ } )
564664 . mockResolvedValueOnce ( {
565665 success : true ,
566666 data : { uri : "at://did:plc:test/org.hypercerts.claim.record/def" , cid : "hypercert-cid" } ,
0 commit comments