@@ -441,6 +441,105 @@ describe('releases/github', () => {
441441 // Should return the newest release that has the matching asset.
442442 expect ( tag ) . toBe ( 'node-smol-20260112-newer' )
443443 } )
444+
445+ it ( 'should skip releases with no assets' , async ( ) => {
446+ // Mock releases where the newest has no assets (empty placeholder release).
447+ const releasesWithEmpty = [
448+ {
449+ assets : [ ] , // Empty release (no binaries built yet)
450+ published_at : '2026-01-13T03:06:00Z' , // Newest but empty
451+ tag_name : 'node-smol-20260113-121d029' ,
452+ } ,
453+ {
454+ assets : [ { name : 'node-darwin-arm64' } , { name : 'node-linux-x64' } ] ,
455+ published_at : '2025-12-26T00:17:00Z' , // Older but has assets
456+ tag_name : 'node-smol-20251226-2126245' ,
457+ } ,
458+ ]
459+
460+ vi . mocked ( httpRequest ) . mockResolvedValue (
461+ createMockHttpResponse (
462+ Buffer . from ( JSON . stringify ( releasesWithEmpty ) ) ,
463+ true ,
464+ 200 ,
465+ ) ,
466+ )
467+
468+ const tag = await getLatestRelease ( 'node-smol-' , SOCKET_BTM_REPO , {
469+ quiet : true ,
470+ } )
471+
472+ // Should skip the empty release and return the older release with assets.
473+ expect ( tag ) . toBe ( 'node-smol-20251226-2126245' )
474+ } )
475+
476+ it ( 'should return null when all matching releases have no assets' , async ( ) => {
477+ // All releases matching prefix are empty.
478+ const allEmpty = [
479+ {
480+ assets : [ ] ,
481+ published_at : '2026-01-13T03:06:00Z' ,
482+ tag_name : 'binject-20260113-121d029' ,
483+ } ,
484+ {
485+ assets : [ ] ,
486+ published_at : '2026-01-13T03:05:00Z' ,
487+ tag_name : 'binject-20260113-abc1234' ,
488+ } ,
489+ ]
490+
491+ vi . mocked ( httpRequest ) . mockResolvedValue (
492+ createMockHttpResponse (
493+ Buffer . from ( JSON . stringify ( allEmpty ) ) ,
494+ true ,
495+ 200 ,
496+ ) ,
497+ )
498+
499+ const tag = await getLatestRelease ( 'binject-' , SOCKET_BTM_REPO , {
500+ quiet : true ,
501+ } )
502+
503+ // Should return null since all matching releases are empty.
504+ expect ( tag ) . toBeNull ( )
505+ } )
506+
507+ it ( 'should skip empty releases when asset pattern is provided' , async ( ) => {
508+ // Mix of empty releases and releases with assets.
509+ const mixedReleases = [
510+ {
511+ assets : [ ] , // Empty
512+ published_at : '2026-01-13T03:00:00Z' ,
513+ tag_name : 'models-20260113-empty' ,
514+ } ,
515+ {
516+ assets : [ { name : 'models-embeddings.bin' } ] , // Wrong asset
517+ published_at : '2026-01-12T12:00:00Z' ,
518+ tag_name : 'models-20260112-wrong' ,
519+ } ,
520+ {
521+ assets : [ { name : 'models-data.tar.gz' } ] , // Correct asset
522+ published_at : '2026-01-11T12:00:00Z' ,
523+ tag_name : 'models-20260111-correct' ,
524+ } ,
525+ ]
526+
527+ vi . mocked ( httpRequest ) . mockResolvedValue (
528+ createMockHttpResponse (
529+ Buffer . from ( JSON . stringify ( mixedReleases ) ) ,
530+ true ,
531+ 200 ,
532+ ) ,
533+ )
534+
535+ const tag = await getLatestRelease ( 'models-' , SOCKET_BTM_REPO , {
536+ assetPattern : '*.tar.gz' ,
537+ quiet : true ,
538+ } )
539+
540+ // Should skip empty release and release without matching asset.
541+ expect ( tag ) . toBe ( 'models-20260111-correct' )
542+ } )
444543 } )
445544
446545 describe ( 'getReleaseAssetUrl' , ( ) => {
0 commit comments