@@ -467,6 +467,111 @@ function matchConstellationApi(urlString) {
467467 return json ( null )
468468}
469469
470+ const BLUESKY_EMBED_DID = 'did:plc:2gkh62xvzokhlf6li4ol3b3d'
471+
472+ /**
473+ * @param {string } urlString
474+ * @returns {MockResponse | null }
475+ */
476+ function matchBlueskyApi ( urlString ) {
477+ const url = new URL ( urlString )
478+
479+ if ( url . pathname === '/xrpc/com.atproto.identity.resolveHandle' ) {
480+ return json ( { did : BLUESKY_EMBED_DID } )
481+ }
482+
483+ if ( url . pathname === '/xrpc/app.bsky.feed.getPosts' ) {
484+ const requestedUri =
485+ url . searchParams . getAll ( 'uris' ) [ 0 ] ||
486+ `at://${ BLUESKY_EMBED_DID } /app.bsky.feed.post/3md3cmrg56k2r`
487+
488+ return json ( {
489+ posts : [
490+ {
491+ uri : requestedUri ,
492+ author : {
493+ did : BLUESKY_EMBED_DID ,
494+ handle : 'danielroe.dev' ,
495+ displayName : 'Daniel Roe' ,
496+ avatar : `https://cdn.bsky.app/img/avatar/plain/${ BLUESKY_EMBED_DID } /mock-avatar@jpeg` ,
497+ } ,
498+ record : {
499+ text : 'Mock Bluesky post for CSP coverage.' ,
500+ createdAt : '2026-03-03T12:00:00.000Z' ,
501+ } ,
502+ embed : {
503+ $type : 'app.bsky.embed.images#view' ,
504+ images : [
505+ {
506+ thumb : `https://cdn.bsky.app/img/feed_thumbnail/plain/${ BLUESKY_EMBED_DID } /mock-image@jpeg` ,
507+ fullsize : `https://cdn.bsky.app/img/feed_fullsize/plain/${ BLUESKY_EMBED_DID } /mock-image@jpeg` ,
508+ alt : 'Mock Bluesky image' ,
509+ aspectRatio : { width : 1200 , height : 630 } ,
510+ } ,
511+ ] ,
512+ } ,
513+ likeCount : 42 ,
514+ replyCount : 7 ,
515+ repostCount : 3 ,
516+ } ,
517+ ] ,
518+ } )
519+ }
520+
521+ if ( url . pathname === '/xrpc/app.bsky.actor.getProfiles' ) {
522+ const actors = url . searchParams . getAll ( 'actors' )
523+
524+ return json ( {
525+ profiles : actors . map ( handle => ( {
526+ handle,
527+ avatar : `https://cdn.bsky.app/img/avatar/plain/${ BLUESKY_EMBED_DID } /mock-avatar` ,
528+ } ) ) ,
529+ } )
530+ }
531+
532+ return null
533+ }
534+
535+ /**
536+ * @param {string } _urlString
537+ * @returns {MockResponse }
538+ */
539+ function matchBlueskyCdn ( _urlString ) {
540+ return {
541+ status : 200 ,
542+ contentType : 'image/svg+xml' ,
543+ body :
544+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120">' +
545+ '<rect width="120" height="120" fill="#0ea5e9"/>' +
546+ '<circle cx="60" cy="44" r="18" fill="#f8fafc"/>' +
547+ '<rect x="24" y="74" width="72" height="18" rx="9" fill="#f8fafc"/>' +
548+ '</svg>' ,
549+ }
550+ }
551+
552+ /**
553+ * @param {string } urlString
554+ * @returns {MockResponse | null }
555+ */
556+ function matchStarHistoryApi ( urlString ) {
557+ const url = new URL ( urlString )
558+
559+ if ( url . pathname === '/svg' ) {
560+ return {
561+ status : 200 ,
562+ contentType : 'image/svg+xml' ,
563+ body :
564+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 320">' +
565+ '<rect width="640" height="320" fill="#0f172a"/>' +
566+ '<path d="M32 256 L160 220 L288 168 L416 120 L544 88 L608 64" stroke="#f59e0b" stroke-width="8" fill="none"/>' +
567+ '<text x="32" y="44" fill="#f8fafc" font-family="monospace" font-size="24">Mock Star History</text>' +
568+ '</svg>' ,
569+ }
570+ }
571+
572+ return null
573+ }
574+
470575/**
471576 * @param {string } urlString
472577 * @returns {MockResponse | null }
@@ -524,6 +629,13 @@ const routes = [
524629 pattern : 'https://constellation.microcosm.blue/**' ,
525630 match : matchConstellationApi ,
526631 } ,
632+ { name : 'Bluesky API' , pattern : 'https://public.api.bsky.app/**' , match : matchBlueskyApi } ,
633+ { name : 'Bluesky CDN' , pattern : 'https://cdn.bsky.app/**' , match : matchBlueskyCdn } ,
634+ {
635+ name : 'Star History API' ,
636+ pattern : 'https://api.star-history.com/**' ,
637+ match : matchStarHistoryApi ,
638+ } ,
527639]
528640
529641/**
0 commit comments