import { CurrentEnvironment } from './util' ; import Config from './config' ; import { TwitchBitsProduct , TwitchBitsTransaction } from './twitch' ; import mxy from './muxy' ; declare global { interface Window { MEDKIT_PURCHASABLE_ITEMS : Product [ ] ; } } export enum PurchaseClientType { Dev , Server , Test , Twitch , Unknown } export type TransactionResponse = Record < string , never > ; export interface PurchaseClient { getProducts ( ) : Promise < Product [ ] > ; purchase ( sku ) : void ; onUserPurchase ( callback ) : void ; onUserPurchaseCanceled ( callback ) : void ; } export interface Cost { amount : number ; type : string ; } export interface Product { sku : string ; displayName : string ; cost : Cost ; } export interface Transaction { transactionId : string ; product : Product ; userId : string ; displayName : string ; initiator : any ; transactionReceipt : string ; } export class TwitchPurchaseClient implements PurchaseClient { private purchaseCallbacks : Array < ( tx : Transaction , promise : Promise < TransactionResponse > ) => void > = [ ] ; private cancelationCallbacks : Array < ( ) => void > = [ ] ; private identifier : string = "" ; constructor ( id ) { if ( ! window ?. Twitch ?. ext ?. bits ) { throw new Error ( 'Twitch helper is required for bits transactions not loaded.' ) ; } this . identifier = id ; window . Twitch . ext . bits . onTransactionComplete ( ( tx ) => { if ( tx . initiator . toLowerCase ( ) === 'current_user' ) { let promise = Promise . resolve < TransactionResponse > ( { } ) ; if ( mxy . transactionsEnabled ) { promise = mxy . client . sendTransactionToServer ( this . identifier , tx ) as Promise < TransactionResponse > ; } this . purchaseCallbacks . forEach ( ( cb ) => cb ( tx , promise ) ) ; } } ) ; window . Twitch . ext . bits . onTransactionCancelled ( ( ) => { this . cancelationCallbacks . forEach ( ( cb ) => cb ( ) ) ; } ) ; } since throws param sku example public purchase ( sku ) { window . Twitch . ext . bits . useBits ( sku ) ; } async since throws return { Promise < [ ] TwitchBitsProduct>} Resolves with an array of  TwitchBitsProduct * objects for each available sku.
     *
     *  example public getProducts ( ) { return window . Twitch . ext . bits . getProducts ( ) ; } since throws param callback example public onUserPurchase ( callback ) { this . purchaseCallbacks . push ( callback ) ; } since throws param callback example public onUserPurchaseCanceled ( callback ) { this . cancelationCallbacks . push ( callback ) ; } } export class DevPurchaseClient implements PurchaseClient { private purchaseCallbacks : Array < ( tx : Transaction , promise : Promise < TransactionResponse > ) => void > = [ ] ; private identifier : string = "" ; public constructor ( id ) { this . identifier = id ; } since param sku example public async purchase ( sku ) { if ( 'MEDKIT_PURCHASABLE_ITEMS' in window ) { const products = await this . getProducts ( ) ; const item = products . find ( ( p ) => p . sku === sku ) ; setTimeout ( ( ) => { if ( item ) { const tx = { transactionId : 'dev-transaction-id' , product : item , userId : 'dev-test-user' , displayName : 'DevTestUser' , initiator : 'current_user' , transactionReceipt : 'transaction-receipt' } ; let promise = Promise . resolve < TransactionResponse > ( { } ) ; if ( mxy . transactionsEnabled ) { promise = mxy . client . sendTransactionToServer ( this . identifier , tx ) as Promise < TransactionResponse > ; } this . purchaseCallbacks . forEach ( ( cb ) => cb ( tx , promise ) ) ; } else { throw new Error ( `Product with SKU "${ sku }" not found in product list.` ) ; } } , 3000 ) ; } else { throw new Error ( 'No development products set. Use "window.MEDKIT_PURCHASABLE_ITEMS" to set debugging products.' ) ; } } async since return { < [ ] Product>} Returns an array of  Product * objects for each available sku.
     *
     *  example public getProducts ( ) { return Promise . resolve ( window . MEDKIT_PURCHASABLE_ITEMS || [ ] ) ; } since param callback example public onUserPurchase ( callback ) { this . purchaseCallbacks . push ( callback ) ; } since param callback example public onUserPurchaseCanceled ( callback ) { } } export class TestPurchaseClient implements PurchaseClient { private purchaseCallbacks : Array < ( tx : Transaction , promise : Promise < TransactionResponse > ) => void > = [ ] ; private purchaseCanceledCallbacks : Array < ( tx : Transaction ) => void > = [ ] ; private identifier : string = "" ; public constructor ( id ) { this . identifier = id ; } since param sku example public purchase ( sku ) { if ( 'MEDKIT_PURCHASABLE_ITEMS' in window ) { const devItems = this . getProducts ( ) ; const products = Object . keys ( devItems ) . map ( ( sku ) => devItems [ sku ] ) ; const foundItem = products . find ( ( sku ) => sku === sku ) ; setTimeout ( ( ) => { if ( foundItem ) { const tx = { transactionId : 'dev-transaction-id' , product : foundItem , userId : 'dev-test-user' , displayName : 'DevTestUser' , initiator : 'current_user' , transactionReceipt : 'transaction-receipt' } ; let promise = Promise . resolve < TransactionResponse > ( { } ) ; if ( mxy . transactionsEnabled ) { promise = mxy . client . sendTransactionToServer ( this . identifier , tx ) as Promise < TransactionResponse > ; } this . purchaseCallbacks . forEach ( function ( callback ) { callback ( tx , promise ) ; } ) ; } else { throw new Error ( `Product with SKU ${ sku } not found in product list.` ) ; } } , 3000 ) ; } else { throw new Error ( 'No development products set. Use "window.MEDKIT_PURCHASABLE_ITEMS" to set debugging products.' ) ; } } async since return { < [ ] Product>} Returns an array of test  Product * objects for each available sku.
     *
     *  example public getProducts ( ) { return Promise . resolve ( window . MEDKIT_PURCHASABLE_ITEMS || [ ] ) ; } since param callback example public onUserPurchase ( callback ) { this . purchaseCallbacks . push ( callback ) ; } since param callback example public onUserPurchaseCanceled ( callback ) { this . purchaseCanceledCallbacks . push ( callback ) ; } } export default function DefaultPurchaseClient ( identifier ) { const type = Config . DefaultPurchaseClientType ( CurrentEnvironment ( ) ) ; switch ( type ) { case PurchaseClientType . Dev : return new DevPurchaseClient ( identifier ) ; case PurchaseClientType . Test : return new TestPurchaseClient ( identifier ) ; case PurchaseClientType . Twitch : return new TwitchPurchaseClient ( identifier ) ; default : throw new Error ( 'Could not determine proper transaction type for environment.' ) ; } }