@@ -210,8 +210,9 @@ describe("Builder", () => {
210210 expect ( bytes . length ) . toBeGreaterThan ( 0 ) ;
211211
212212 const reader = await Reader . fromAsset ( dest ) ;
213- const manifestStore = reader . json ( ) ;
214- const activeManifest = reader . getActive ( ) ;
213+ expect ( reader ) . not . toBeNull ( ) ;
214+ const manifestStore = reader ! . json ( ) ;
215+ const activeManifest = reader ! . getActive ( ) ;
215216 expect ( manifestStore . validation_status ! [ 0 ] . code ) . toBe (
216217 "signingCredential.untrusted" ,
217218 ) ;
@@ -237,7 +238,8 @@ describe("Builder", () => {
237238
238239 // Read and verify the assertion in the signed manifest
239240 const reader = await Reader . fromAsset ( dest ) ;
240- const activeManifest = reader . getActive ( ) ;
241+ expect ( reader ) . not . toBeNull ( ) ;
242+ const activeManifest = reader ! . getActive ( ) ;
241243 const cborAssertion = activeManifest ?. assertions ?. find (
242244 ( a : any ) => a . label === "c2pa.actions.v2" ,
243245 ) ;
@@ -265,8 +267,9 @@ describe("Builder", () => {
265267 buffer : dest . buffer ! as Buffer ,
266268 mimeType : "jpeg" ,
267269 } ) ;
268- const manifestStore = reader . json ( ) ;
269- const activeManifest = reader . getActive ( ) ;
270+ expect ( reader ) . not . toBeNull ( ) ;
271+ const manifestStore = reader ! . json ( ) ;
272+ const activeManifest = reader ! . getActive ( ) ;
270273 expect ( manifestStore . validation_status ! [ 0 ] . code ) . toBe (
271274 "signingCredential.untrusted" ,
272275 ) ;
@@ -296,8 +299,9 @@ describe("Builder", () => {
296299 expect ( bytes . length ) . toBeGreaterThan ( 0 ) ;
297300
298301 const reader = await Reader . fromAsset ( dest ) ;
299- const manifestStore = reader . json ( ) ;
300- const activeManifest = reader . getActive ( ) ;
302+ expect ( reader ) . not . toBeNull ( ) ;
303+ const manifestStore = reader ! . json ( ) ;
304+ const activeManifest = reader ! . getActive ( ) ;
301305 expect ( manifestStore . validation_status ! [ 0 ] . code ) . toBe (
302306 "signingCredential.untrusted" ,
303307 ) ;
@@ -330,8 +334,9 @@ describe("Builder", () => {
330334 buffer : dest . buffer ! as Buffer ,
331335 mimeType : "jpeg" ,
332336 } ) ;
333- const manifestStore = reader . json ( ) ;
334- const activeManifest = reader . getActive ( ) ;
337+ expect ( reader ) . not . toBeNull ( ) ;
338+ const manifestStore = reader ! . json ( ) ;
339+ const activeManifest = reader ! . getActive ( ) ;
335340 expect ( manifestStore . validation_status ! [ 0 ] . code ) . toBe (
336341 "signingCredential.untrusted" ,
337342 ) ;
@@ -360,8 +365,9 @@ describe("Builder", () => {
360365 buffer : dest . buffer ! as Buffer ,
361366 mimeType : "jpeg" ,
362367 } ) ;
363- const manifestStore = reader . json ( ) ;
364- const activeManifest = reader . getActive ( ) ;
368+ expect ( reader ) . not . toBeNull ( ) ;
369+ const manifestStore = reader ! . json ( ) ;
370+ const activeManifest = reader ! . getActive ( ) ;
365371 expect ( manifestStore . validation_status ! [ 0 ] . code ) . toBe (
366372 "signingCredential.untrusted" ,
367373 ) ;
@@ -390,7 +396,8 @@ describe("Builder", () => {
390396 builder . sign ( signer , source , dest ) ;
391397
392398 const reader = await Reader . fromAsset ( dest ) ;
393- const manifest = reader . json ( ) ;
399+ expect ( reader ) . not . toBeNull ( ) ;
400+ const manifest = reader ! . json ( ) ;
394401
395402 // Check that our specific JSON assertion doesn't have escaped characters
396403 const activeManifest = manifest . manifests [ manifest . active_manifest ! ] ;
@@ -475,7 +482,8 @@ describe("Builder", () => {
475482 buffer : dest . buffer ! as Buffer ,
476483 mimeType : "jpeg" ,
477484 } ) ;
478- const manifestStore = reader . json ( ) ;
485+ expect ( reader ) . not . toBeNull ( ) ;
486+ const manifestStore = reader ! . json ( ) ;
479487 expect ( JSON . stringify ( manifestStore ) ) . toContain ( "Test Ingredient" ) ;
480488 expect ( JSON . stringify ( manifestStore ) ) . toContain ( "thumbnail.ingredient" ) ;
481489 } ) ;
@@ -485,7 +493,8 @@ describe("Builder", () => {
485493
486494 // Create a reader to get the parent manifest label from the existing source
487495 const reader = await Reader . fromAsset ( source ) ;
488- const parentManifestLabel = reader . activeLabel ( ) ;
496+ expect ( reader ) . not . toBeNull ( ) ;
497+ const parentManifestLabel = reader ! . activeLabel ( ) ;
489498 expect ( parentManifestLabel ) . toBeDefined ( ) ;
490499
491500 // Create a redacted URI for the assertion we are going to redact
@@ -550,10 +559,11 @@ describe("Builder", () => {
550559 buffer : dest . buffer ! as Buffer ,
551560 mimeType : "image/jpeg" ,
552561 } ) ;
562+ expect ( signedReader ) . not . toBeNull ( ) ;
553563 expect ( signedReader ) . toBeDefined ( ) ;
554564
555565 // Check that the manifest was created successfully
556- const activeManifest = signedReader . getActive ( ) ;
566+ const activeManifest = signedReader ! . getActive ( ) ;
557567 expect ( activeManifest ) . toBeDefined ( ) ;
558568
559569 // Verify the redacted action was added
@@ -643,9 +653,112 @@ describe("Builder", () => {
643653 } ) ;
644654
645655 // Check if the manifest has the expected structure
646- const activeManifest = reader . getActive ( ) ;
656+ const activeManifest = reader ! . getActive ( ) ;
647657 expect ( activeManifest ) . toBeDefined ( ) ;
648658 expect ( activeManifest ?. title ) . toBe ( "Test_Manifest" ) ;
649659 } ) ;
660+
661+ it ( "should add action using addAction method" , async ( ) => {
662+ const simpleManifestDefinition = {
663+ claim_generator_info : [
664+ {
665+ name : "c2pa_test" ,
666+ version : "1.0.0" ,
667+ } ,
668+ ] ,
669+ title : "Test_AddAction" ,
670+ format : "image/jpeg" ,
671+ assertions : [ ] ,
672+ resources : { resources : { } } ,
673+ } ;
674+
675+ const builder = Builder . withJson ( simpleManifestDefinition ) ;
676+
677+ // Add an action using addAction method
678+ // The action needs to be a structured object matching the c2pa Action type
679+ const actionJson = JSON . stringify ( {
680+ action : "c2pa.edited" ,
681+ } ) ;
682+ builder . addAction ( actionJson ) ;
683+
684+ // Sign the manifest
685+ const dest = { path : path . join ( tempDir , "add_action_test.jpg" ) } ;
686+ const signer = LocalSigner . newSigner ( publicKey , privateKey , "es256" ) ;
687+ builder . sign ( signer , source , dest ) ;
688+
689+ // Verify the action was added
690+ const reader = await Reader . fromAsset ( dest ) ;
691+ expect ( reader ) . not . toBeNull ( ) ;
692+ const activeManifest = reader ! . getActive ( ) ;
693+ const actionsAssertion = activeManifest ?. assertions ?. find (
694+ ( a : any ) => a . label === "c2pa.actions.v2" ,
695+ ) ;
696+ expect ( actionsAssertion ) . toBeDefined ( ) ;
697+ if ( isActionsAssertion ( actionsAssertion ) ) {
698+ const actions = actionsAssertion . data . actions ;
699+ const editedAction = actions . find ( ( a : any ) => a . action === "c2pa.edited" ) ;
700+ expect ( editedAction ) . toBeDefined ( ) ;
701+ expect ( editedAction ?. action ) . toBe ( "c2pa.edited" ) ;
702+ } else {
703+ throw new Error ( "Actions assertion does not have the expected structure" ) ;
704+ }
705+ } ) ;
706+
707+ it ( "should add ingredient using addIngredient method" , async ( ) => {
708+ const simpleManifestDefinition = {
709+ claim_generator_info : [
710+ {
711+ name : "c2pa_test" ,
712+ version : "1.0.0" ,
713+ } ,
714+ ] ,
715+ title : "Test_AddIngredient" ,
716+ format : "image/jpeg" ,
717+ ingredients : [ ] ,
718+ assertions : [
719+ {
720+ label : "c2pa.actions" ,
721+ data : {
722+ actions : [
723+ {
724+ action : "c2pa.created" ,
725+ digitalSourceType : "http://c2pa.org/digitalsourcetype/empty" ,
726+ } ,
727+ ] ,
728+ } ,
729+ } ,
730+ ] ,
731+ resources : { resources : { } } ,
732+ } ;
733+
734+ const builder = Builder . withJson ( simpleManifestDefinition ) ;
735+
736+ // Add an ingredient using addIngredient method
737+ const ingredientJson = JSON . stringify ( {
738+ title : "Test Ingredient via addIngredient" ,
739+ format : "image/jpeg" ,
740+ instance_id : "ingredient-12345" ,
741+ relationship : "componentOf" ,
742+ } ) ;
743+ builder . addIngredient ( ingredientJson ) ;
744+
745+ // Sign the manifest
746+ const dest = { path : path . join ( tempDir , "add_ingredient_test.jpg" ) } ;
747+ const signer = LocalSigner . newSigner ( publicKey , privateKey , "es256" ) ;
748+ builder . sign ( signer , source , dest ) ;
749+
750+ // Verify the ingredient was added
751+ const reader = await Reader . fromAsset ( dest ) ;
752+ expect ( reader ) . not . toBeNull ( ) ;
753+ const activeManifest = reader ! . getActive ( ) ;
754+ expect ( activeManifest ?. ingredients ) . toBeDefined ( ) ;
755+ expect ( activeManifest ?. ingredients ?. length ) . toBeGreaterThan ( 0 ) ;
756+ const addedIngredient = activeManifest ?. ingredients ?. find (
757+ ( ing : any ) => ing . title === "Test Ingredient via addIngredient" ,
758+ ) ;
759+ expect ( addedIngredient ) . toBeDefined ( ) ;
760+ expect ( addedIngredient ?. instance_id ) . toBe ( "ingredient-12345" ) ;
761+ expect ( addedIngredient ?. relationship ) . toBe ( "componentOf" ) ;
762+ } ) ;
650763 } ) ;
651764} ) ;
0 commit comments