11import assert from 'node:assert/strict' ;
2+ import fs from 'node:fs/promises' ;
3+ import path from 'node:path' ;
24import { describe , it } from 'node:test' ;
35import { HAGICODE_SPONSOR_PLAN_STORE_ID } from '../../types/subscription.js' ;
46import { HAGICODE_TURBOENGINE_STORE_ID , turboEngineProductConfig } from '../../types/turboengine-license.js' ;
@@ -7,7 +9,9 @@ import type {
79 RawStoreSubscriptionState ,
810 SubscriptionPlatformBroker ,
911} from '../subscription/subscription-broker.js' ;
10- import { buildSupportedStateFromMinimalStoreApis , MicrosoftStoreSubscriptionBroker } from '../subscription/subscription-broker.js' ;
12+ import { buildSupportedStateFromProductQueries , MicrosoftStoreSubscriptionBroker } from '../subscription/subscription-broker.js' ;
13+
14+ const brokerPath = path . resolve ( process . cwd ( ) , 'src/main/subscription/subscription-broker.ts' ) ;
1115
1216class MockPlatformBroker implements SubscriptionPlatformBroker {
1317 constructor (
@@ -32,8 +36,24 @@ function toWinRtDateTime(isoString: string): { universalTime: bigint } {
3236 } ;
3337}
3438
39+ function createProductQueryResult ( products : Record < string , Record < string , unknown > > ) : {
40+ products : {
41+ hasKey : ( key : string ) => boolean ;
42+ get : ( key : string ) => Record < string , unknown > | undefined ;
43+ } ;
44+ extendedError : 0 ;
45+ } {
46+ return {
47+ products : {
48+ hasKey : ( key ) => Object . prototype . hasOwnProperty . call ( products , key ) ,
49+ get : ( key ) => products [ key ] ,
50+ } ,
51+ extendedError : 0 ,
52+ } ;
53+ }
54+
3555describe ( 'subscription broker' , ( ) => {
36- it ( 'passes the native window handle to the dynwinrt adapter as a bigint' , async ( ) => {
56+ it ( 'passes the native window handle to the broker adapter as a bigint' , async ( ) => {
3757 let observedHandle : bigint | null = null ;
3858
3959 const broker = new MicrosoftStoreSubscriptionBroker ( {
@@ -67,83 +87,124 @@ describe('subscription broker', () => {
6787 assert . equal ( observedHandle , 0x12345678n ) ;
6888 } ) ;
6989
70- it ( 'returns an unavailable snapshot when dynwinrt initialization fails' , async ( ) => {
90+ it ( 'returns an unavailable snapshot when native addon broker initialization fails' , async ( ) => {
7191 const broker = new MicrosoftStoreSubscriptionBroker ( {
7292 adapterFactory : async ( ) => {
73- throw new Error ( 'dynwinrt bindings missing' ) ;
93+ throw new Error ( 'native addon missing' ) ;
7494 } ,
7595 } ) ;
7696
7797 const status = await broker . queryStatus ( ) ;
7898 const purchase = await broker . purchase ( ) ;
7999
80100 assert . equal ( status . availability , 'store-unavailable' ) ;
81- assert . match ( status . errorMessage ?? '' , / d y n w i n r t b i n d i n g s m i s s i n g / ) ;
101+ assert . match ( status . errorMessage ?? '' , / n a t i v e a d d o n m i s s i n g / ) ;
82102 assert . equal ( purchase . outcome , 'not-supported' ) ;
83- assert . match ( purchase . errorMessage ?? '' , / d y n w i n r t b i n d i n g s m i s s i n g / ) ;
103+ assert . match ( purchase . errorMessage ?? '' , / n a t i v e a d d o n m i s s i n g / ) ;
84104 } ) ;
85105
86- it ( 'builds a supported snapshot from license and eligibility APIs without product queries' , ( ) => {
106+ it ( 'builds a supported subscription snapshot from associated and collection product queries' , ( ) => {
87107 const expirationDate = '2026-07-01T00:00:00.000Z' ;
88- const state = buildSupportedStateFromMinimalStoreApis ( {
108+ const state = buildSupportedStateFromProductQueries ( {
89109 fetchedAt : '2026-06-14T06:00:00.000Z' ,
90- appLicense : {
91- isActive : true ,
92- addOnLicenses : {
93- hasKey : ( key ) => key === HAGICODE_SPONSOR_PLAN_STORE_ID ,
94- get : ( key ) => ( key === HAGICODE_SPONSOR_PLAN_STORE_ID
95- ? {
96- skuStoreId : HAGICODE_SPONSOR_PLAN_STORE_ID ,
97- isActive : true ,
98- expirationDate : toWinRtDateTime ( expirationDate ) ,
99- }
100- : undefined ) ,
110+ associatedQueryResult : createProductQueryResult ( {
111+ [ HAGICODE_SPONSOR_PLAN_STORE_ID ] : {
112+ storeId : HAGICODE_SPONSOR_PLAN_STORE_ID ,
113+ title : 'Hagicode Sponsor Plan' ,
114+ isInUserCollection : false ,
115+ skus : [
116+ {
117+ storeId : `${ HAGICODE_SPONSOR_PLAN_STORE_ID } /0010` ,
118+ title : 'Monthly subscription' ,
119+ isSubscription : true ,
120+ isInUserCollection : false ,
121+ collectionData : {
122+ endDate : toWinRtDateTime ( expirationDate ) ,
123+ } ,
124+ } ,
125+ ] ,
101126 } ,
102- } ,
103- canAcquireResult : {
104- status : 1 ,
105- extendedError : 0 ,
106- } ,
107- canLicenseStatusEnum : {
108- Licensable : 1 ,
109- } ,
127+ } ) ,
128+ collectionQueryResult : createProductQueryResult ( {
129+ [ HAGICODE_SPONSOR_PLAN_STORE_ID ] : {
130+ storeId : HAGICODE_SPONSOR_PLAN_STORE_ID ,
131+ title : 'Hagicode Sponsor Plan' ,
132+ isInUserCollection : true ,
133+ skus : [
134+ {
135+ storeId : `${ HAGICODE_SPONSOR_PLAN_STORE_ID } /0010` ,
136+ title : 'Monthly subscription' ,
137+ isSubscription : true ,
138+ isInUserCollection : true ,
139+ collectionData : {
140+ endDate : toWinRtDateTime ( expirationDate ) ,
141+ } ,
142+ } ,
143+ ] ,
144+ } ,
145+ } ) ,
110146 } ) ;
111147
112148 assert . equal ( state . availability , 'supported' ) ;
113149 assert . equal ( state . product ?. storeId , HAGICODE_SPONSOR_PLAN_STORE_ID ) ;
114- assert . equal ( state . license ?. isActive , true ) ;
115- assert . equal ( state . license ?. expirationDate , expirationDate ) ;
116- assert . equal ( state . purchaseEligibility , 'licensable' ) ;
150+ assert . equal ( state . product ?. isInUserCollection , true ) ;
151+ assert . equal ( state . sku ?. isInUserCollection , true ) ;
152+ assert . equal ( state . sku ?. collectionEndDate , expirationDate ) ;
153+ assert . equal ( state . license , null ) ;
154+ assert . equal ( state . purchaseEligibility , 'license-action-not-applicable' ) ;
117155 assert . equal ( state . errorCode , null ) ;
118156 } ) ;
119157
120- it ( 'uses product-configured Store IDs when reading TurboEngine ownership' , ( ) => {
121- const state = buildSupportedStateFromMinimalStoreApis ( {
158+ it ( 'uses product-configured Store IDs when reading TurboEngine ownership from collection queries ' , ( ) => {
159+ const state = buildSupportedStateFromProductQueries ( {
122160 fetchedAt : '2026-06-14T06:00:00.000Z' ,
123- appLicense : {
124- isActive : true ,
125- addOnLicenses : {
126- hasKey : ( key ) => key === HAGICODE_TURBOENGINE_STORE_ID ,
127- get : ( key ) => ( key === HAGICODE_TURBOENGINE_STORE_ID
128- ? {
129- skuStoreId : HAGICODE_TURBOENGINE_STORE_ID ,
130- isActive : true ,
131- }
132- : undefined ) ,
161+ associatedQueryResult : createProductQueryResult ( {
162+ [ HAGICODE_TURBOENGINE_STORE_ID ] : {
163+ storeId : HAGICODE_TURBOENGINE_STORE_ID ,
164+ title : 'TurboEngine' ,
165+ isInUserCollection : false ,
166+ skus : [
167+ {
168+ storeId : `${ HAGICODE_TURBOENGINE_STORE_ID } /0010` ,
169+ title : 'TurboEngine durable' ,
170+ isSubscription : false ,
171+ isInUserCollection : false ,
172+ } ,
173+ ] ,
133174 } ,
134- } ,
135- canAcquireResult : {
136- status : 1 ,
137- extendedError : 0 ,
138- } ,
139- canLicenseStatusEnum : {
140- Licensable : 1 ,
141- } ,
175+ } ) ,
176+ collectionQueryResult : createProductQueryResult ( {
177+ [ HAGICODE_TURBOENGINE_STORE_ID ] : {
178+ storeId : HAGICODE_TURBOENGINE_STORE_ID ,
179+ title : 'TurboEngine' ,
180+ isInUserCollection : true ,
181+ skus : [
182+ {
183+ storeId : `${ HAGICODE_TURBOENGINE_STORE_ID } /0010` ,
184+ title : 'TurboEngine durable' ,
185+ isSubscription : false ,
186+ isInUserCollection : true ,
187+ } ,
188+ ] ,
189+ } ,
190+ } ) ,
142191 productConfig : turboEngineProductConfig ,
143192 } ) ;
144193
145194 assert . equal ( state . product ?. storeId , HAGICODE_TURBOENGINE_STORE_ID ) ;
146195 assert . equal ( state . product ?. title , 'TurboEngine' ) ;
147- assert . equal ( state . license ?. isActive , true ) ;
196+ assert . equal ( state . product ?. isInUserCollection , true ) ;
197+ assert . equal ( state . sku ?. isInUserCollection , true ) ;
198+ assert . equal ( state . purchaseEligibility , 'license-action-not-applicable' ) ;
148199 } ) ;
200+
201+ it ( 'routes reads and purchases through the packaged native addon without a dynwinrt JS fallback' , async ( ) => {
202+ const source = await fs . readFile ( brokerPath , 'utf8' ) ;
203+
204+ assert . match ( source , / e x e c u t e W i n d o w s S t o r e S t a t u s A d d o n \( \{ / ) ;
205+ assert . match ( source , / e x e c u t e W i n d o w s S t o r e P u r c h a s e A d d o n \( \{ / ) ;
206+ assert . doesNotMatch ( source , / S t o r e C o n t e x t \. g e t D e f a u l t / ) ;
207+ assert . doesNotMatch ( source , / @ m i c r o s o f t \/ d y n w i n r t / ) ;
208+ } ) ;
209+
149210} ) ;
0 commit comments