@@ -11,6 +11,8 @@ import {
1111 MarketplaceSearchResponseSchema ,
1212 MarketplaceInstallRequestSchema ,
1313 MarketplaceInstallResponseSchema ,
14+ ArtifactReferenceSchema ,
15+ ArtifactDownloadResponseSchema ,
1416} from './marketplace.zod' ;
1517
1618describe ( 'PublisherVerificationSchema' , ( ) => {
@@ -340,3 +342,116 @@ describe('MarketplaceInstallResponseSchema', () => {
340342 expect ( parsed . success ) . toBe ( false ) ;
341343 } ) ;
342344} ) ;
345+
346+ describe ( 'ArtifactReferenceSchema' , ( ) => {
347+ it ( 'should accept valid artifact reference' , ( ) => {
348+ const ref = {
349+ url : 'https://registry.objectstack.io/packages/com.acme.crm-2.0.0.tgz' ,
350+ sha256 : 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2' ,
351+ size : 1048576 ,
352+ uploadedAt : '2025-06-01T12:00:00Z' ,
353+ } ;
354+ const parsed = ArtifactReferenceSchema . parse ( ref ) ;
355+ expect ( parsed . format ) . toBe ( 'tgz' ) ;
356+ expect ( parsed . size ) . toBe ( 1048576 ) ;
357+ } ) ;
358+
359+ it ( 'should accept zip format' , ( ) => {
360+ const ref = {
361+ url : 'https://registry.objectstack.io/packages/com.acme.crm-2.0.0.zip' ,
362+ sha256 : 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2' ,
363+ size : 2048576 ,
364+ format : 'zip' as const ,
365+ uploadedAt : '2025-06-01T12:00:00Z' ,
366+ } ;
367+ const parsed = ArtifactReferenceSchema . parse ( ref ) ;
368+ expect ( parsed . format ) . toBe ( 'zip' ) ;
369+ } ) ;
370+
371+ it ( 'should reject invalid SHA256' , ( ) => {
372+ expect ( ( ) => ArtifactReferenceSchema . parse ( {
373+ url : 'https://registry.objectstack.io/pkg.tgz' ,
374+ sha256 : 'invalid-hash' ,
375+ size : 1024 ,
376+ uploadedAt : '2025-06-01T12:00:00Z' ,
377+ } ) ) . toThrow ( ) ;
378+ } ) ;
379+
380+ it ( 'should reject non-positive size' , ( ) => {
381+ expect ( ( ) => ArtifactReferenceSchema . parse ( {
382+ url : 'https://registry.objectstack.io/pkg.tgz' ,
383+ sha256 : 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2' ,
384+ size : 0 ,
385+ uploadedAt : '2025-06-01T12:00:00Z' ,
386+ } ) ) . toThrow ( ) ;
387+ } ) ;
388+ } ) ;
389+
390+ describe ( 'ArtifactDownloadResponseSchema' , ( ) => {
391+ it ( 'should accept valid download response' , ( ) => {
392+ const response = {
393+ downloadUrl : 'https://cdn.objectstack.io/artifacts/com.acme.crm-2.0.0.tgz?token=abc' ,
394+ sha256 : 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2' ,
395+ size : 1048576 ,
396+ format : 'tgz' as const ,
397+ expiresAt : '2025-06-01T13:00:00Z' ,
398+ } ;
399+ const parsed = ArtifactDownloadResponseSchema . parse ( response ) ;
400+ expect ( parsed . expiresAt ) . toBe ( '2025-06-01T13:00:00Z' ) ;
401+ } ) ;
402+
403+ it ( 'should accept response without expiration' , ( ) => {
404+ const response = {
405+ downloadUrl : 'https://cdn.objectstack.io/artifacts/com.acme.crm-2.0.0.tgz' ,
406+ sha256 : 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2' ,
407+ size : 1048576 ,
408+ format : 'tgz' as const ,
409+ } ;
410+ const parsed = ArtifactDownloadResponseSchema . parse ( response ) ;
411+ expect ( parsed . expiresAt ) . toBeUndefined ( ) ;
412+ } ) ;
413+ } ) ;
414+
415+ describe ( 'MarketplaceListingSchema - Artifact References' , ( ) => {
416+ it ( 'should accept listing with artifact references in versions' , ( ) => {
417+ const listing = {
418+ id : 'listing-001' ,
419+ packageId : 'com.acme.crm' ,
420+ publisherId : 'pub-001' ,
421+ name : 'Acme CRM' ,
422+ category : 'crm' as const ,
423+ latestVersion : '2.0.0' ,
424+ versions : [
425+ {
426+ version : '2.0.0' ,
427+ releaseDate : '2025-06-01T00:00:00Z' ,
428+ artifact : {
429+ url : 'https://registry.objectstack.io/packages/com.acme.crm-2.0.0.tgz' ,
430+ sha256 : 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2' ,
431+ size : 1048576 ,
432+ uploadedAt : '2025-06-01T00:00:00Z' ,
433+ } ,
434+ } ,
435+ ] ,
436+ } ;
437+ const parsed = MarketplaceListingSchema . parse ( listing ) ;
438+ expect ( parsed . versions ! [ 0 ] . artifact ?. sha256 ) . toBe ( 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2' ) ;
439+ } ) ;
440+ } ) ;
441+
442+ describe ( 'MarketplaceInstallRequestSchema - Artifact Reference' , ( ) => {
443+ it ( 'should accept install request with artifact reference' , ( ) => {
444+ const request = {
445+ listingId : 'listing-001' ,
446+ version : '2.0.0' ,
447+ artifactRef : {
448+ url : 'https://registry.objectstack.io/packages/com.acme.crm-2.0.0.tgz' ,
449+ sha256 : 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2' ,
450+ size : 1048576 ,
451+ uploadedAt : '2025-06-01T00:00:00Z' ,
452+ } ,
453+ } ;
454+ const parsed = MarketplaceInstallRequestSchema . parse ( request ) ;
455+ expect ( parsed . artifactRef ?. url ) . toContain ( 'com.acme.crm' ) ;
456+ } ) ;
457+ } ) ;
0 commit comments