@@ -56,6 +56,15 @@ const createService = () => {
5656 createInsightsTranslationTask : vi . fn ( ) ,
5757 }
5858 const eventEmitter = { emit : vi . fn ( ) }
59+ const entitlementService = {
60+ isPremiumLocked : vi . fn (
61+ async ( input : {
62+ isPremium ?: boolean | null
63+ isOwner : boolean
64+ readerId ?: string
65+ } ) => Boolean ( input . isPremium ) && ! input . isOwner && ! input . readerId ,
66+ ) ,
67+ }
5968 const generationMetrics = {
6069 attachLatest : vi . fn ( async ( _type : string , items : unknown [ ] ) =>
6170 items . map ( ( item ) => ( {
@@ -72,6 +81,7 @@ const createService = () => {
7281 configService as any ,
7382 aiService as any ,
7483 eventEmitter as any ,
84+ entitlementService as any ,
7585 )
7686 const multilang = new MultilangGenerationService (
7787 aiInFlightService as any ,
@@ -94,6 +104,7 @@ const createService = () => {
94104 aiTaskService,
95105 configService,
96106 databaseService,
107+ entitlementService,
97108 eventEmitter,
98109 generationMetrics,
99110 repository,
@@ -270,6 +281,58 @@ describe('AiInsightsService', () => {
270281 ) . rejects . toThrow ( AppException )
271282 } )
272283
284+ it ( 'serves cached insights for a premium post to an entitled reader' , async ( ) => {
285+ const { databaseService, repository, service } = createService ( )
286+ databaseService . findGlobalById . mockResolvedValue ( {
287+ type : CollectionRefTypes . Post ,
288+ document : {
289+ id : 'post-1' ,
290+ title : 'Premium Post' ,
291+ text : 'Premium text' ,
292+ isPublished : true ,
293+ isPremium : true ,
294+ } ,
295+ } )
296+ repository . findByRefAndLang . mockResolvedValue ( {
297+ ...row ,
298+ hash : 'mismatch-so-onlyDb-returns-null' ,
299+ } as any )
300+
301+ await expect (
302+ service . getOrGenerateInsightsForArticle ( 'post-1' , {
303+ lang : 'zh' ,
304+ onlyDb : true ,
305+ readerId : 'reader-1' ,
306+ } ) ,
307+ ) . resolves . toBeNull ( )
308+ } )
309+
310+ it ( 'serves cached insights for a premium post to the owner' , async ( ) => {
311+ const { databaseService, repository, service } = createService ( )
312+ databaseService . findGlobalById . mockResolvedValue ( {
313+ type : CollectionRefTypes . Post ,
314+ document : {
315+ id : 'post-1' ,
316+ title : 'Premium Post' ,
317+ text : 'Premium text' ,
318+ isPublished : true ,
319+ isPremium : true ,
320+ } ,
321+ } )
322+ repository . findByRefAndLang . mockResolvedValue ( {
323+ ...row ,
324+ hash : 'mismatch-so-onlyDb-returns-null' ,
325+ } as any )
326+
327+ await expect (
328+ service . getOrGenerateInsightsForArticle ( 'post-1' , {
329+ lang : 'zh' ,
330+ onlyDb : true ,
331+ isOwner : true ,
332+ } ) ,
333+ ) . resolves . toBeNull ( )
334+ } )
335+
273336 it ( 'does not block background insight regeneration for a premium post' , async ( ) => {
274337 const {
275338 aiTaskService,
0 commit comments