@xyo-network/payment-plugin 3.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +165 -0
- package/README.md +13 -0
- package/dist/neutral/Discount/Diviner.d.ts +19 -0
- package/dist/neutral/Discount/Diviner.d.ts.map +1 -0
- package/dist/neutral/Discount/index.d.ts +3 -0
- package/dist/neutral/Discount/index.d.ts.map +1 -0
- package/dist/neutral/Discount/lib/applyCoupons.d.ts +4 -0
- package/dist/neutral/Discount/lib/applyCoupons.d.ts.map +1 -0
- package/dist/neutral/Discount/lib/index.d.ts +2 -0
- package/dist/neutral/Discount/lib/index.d.ts.map +1 -0
- package/dist/neutral/Invoice/getInvoiceForEscrow.d.ts +6 -0
- package/dist/neutral/Invoice/getInvoiceForEscrow.d.ts.map +1 -0
- package/dist/neutral/Invoice/index.d.ts +2 -0
- package/dist/neutral/Invoice/index.d.ts.map +1 -0
- package/dist/neutral/Subtotal/Diviner.d.ts +12 -0
- package/dist/neutral/Subtotal/Diviner.d.ts.map +1 -0
- package/dist/neutral/Subtotal/index.d.ts +2 -0
- package/dist/neutral/Subtotal/index.d.ts.map +1 -0
- package/dist/neutral/Subtotal/lib/appraisalValidators.d.ts +3 -0
- package/dist/neutral/Subtotal/lib/appraisalValidators.d.ts.map +1 -0
- package/dist/neutral/Subtotal/lib/durationValidators.d.ts +3 -0
- package/dist/neutral/Subtotal/lib/durationValidators.d.ts.map +1 -0
- package/dist/neutral/Subtotal/lib/index.d.ts +3 -0
- package/dist/neutral/Subtotal/lib/index.d.ts.map +1 -0
- package/dist/neutral/Subtotal/lib/termsValidators.d.ts +4 -0
- package/dist/neutral/Subtotal/lib/termsValidators.d.ts.map +1 -0
- package/dist/neutral/Total/Diviner.d.ts +16 -0
- package/dist/neutral/Total/Diviner.d.ts.map +1 -0
- package/dist/neutral/Total/index.d.ts +2 -0
- package/dist/neutral/Total/index.d.ts.map +1 -0
- package/dist/neutral/index.d.ts +5 -0
- package/dist/neutral/index.d.ts.map +1 -0
- package/dist/neutral/index.mjs +347 -0
- package/dist/neutral/index.mjs.map +1 -0
- package/package.json +61 -0
- package/src/Discount/Diviner.ts +155 -0
- package/src/Discount/index.ts +2 -0
- package/src/Discount/lib/applyCoupons.ts +58 -0
- package/src/Discount/lib/index.ts +1 -0
- package/src/Invoice/getInvoiceForEscrow.ts +39 -0
- package/src/Invoice/index.ts +1 -0
- package/src/Subtotal/Diviner.ts +65 -0
- package/src/Subtotal/index.ts +1 -0
- package/src/Subtotal/lib/appraisalValidators.ts +45 -0
- package/src/Subtotal/lib/durationValidators.ts +18 -0
- package/src/Subtotal/lib/index.ts +2 -0
- package/src/Subtotal/lib/termsValidators.ts +18 -0
- package/src/Total/Diviner.ts +67 -0
- package/src/Total/index.ts +1 -0
- package/src/index.ts +4 -0
- package/typedoc.json +5 -0
- package/xy.config.ts +11 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { assertEx } from '@xylabs/assert'
|
|
2
|
+
import { exists } from '@xylabs/exists'
|
|
3
|
+
import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
|
|
4
|
+
import type {
|
|
5
|
+
AmountFields,
|
|
6
|
+
Coupon, Discount, FixedAmountCoupon,
|
|
7
|
+
FixedPercentageCoupon,
|
|
8
|
+
} from '@xyo-network/payment-payload-plugins'
|
|
9
|
+
import {
|
|
10
|
+
DiscountSchema, isFixedAmountCoupon, isFixedPercentageCoupon,
|
|
11
|
+
isStackable,
|
|
12
|
+
} from '@xyo-network/payment-payload-plugins'
|
|
13
|
+
|
|
14
|
+
export const applyCoupons = (appraisals: HashLeaseEstimate[], coupons: Coupon[]): Discount => {
|
|
15
|
+
// Ensure all appraisals and coupons are in USD
|
|
16
|
+
const allAppraisalsAreUSD = appraisals.every(appraisal => appraisal.currency === 'USD')
|
|
17
|
+
assertEx(allAppraisalsAreUSD, 'All appraisals must be in USD')
|
|
18
|
+
const allCouponsAreUSD = coupons.map(coupon => (coupon as Partial<AmountFields>)?.currency).filter(exists).every(currency => currency === 'USD')
|
|
19
|
+
assertEx(allCouponsAreUSD, 'All coupons must be in USD')
|
|
20
|
+
const total = appraisals.reduce((acc, appraisal) => acc + appraisal.price, 0)
|
|
21
|
+
|
|
22
|
+
// Calculated non-stackable discount coupons
|
|
23
|
+
const singularFixedDiscount = Math.max(...coupons
|
|
24
|
+
.filter(coupon => isFixedAmountCoupon(coupon) && !isStackable(coupon))
|
|
25
|
+
.map(coupon => (coupon as FixedAmountCoupon).amount), 0)
|
|
26
|
+
const singularPercentageDiscount = (Math.max(...coupons
|
|
27
|
+
.filter(coupon => isFixedPercentageCoupon(coupon) && !isStackable(coupon))
|
|
28
|
+
.map(coupon => (coupon as FixedPercentageCoupon).percentage), 0)) * total
|
|
29
|
+
|
|
30
|
+
// Calculate stackable discount coupons
|
|
31
|
+
// First calculate the total discount from fixed amount coupons
|
|
32
|
+
const stackedFixedDiscount = coupons
|
|
33
|
+
.filter(coupon => isFixedAmountCoupon(coupon) && isStackable(coupon))
|
|
34
|
+
.reduce((acc, coupon) => acc + (coupon as FixedAmountCoupon).amount, 0)
|
|
35
|
+
// Then calculate the total discount from percentage coupons and apply
|
|
36
|
+
// the percentage discount to the remaining total after fixed discounts
|
|
37
|
+
const stackedPercentageDiscount = coupons
|
|
38
|
+
.filter(coupon => isFixedPercentageCoupon(coupon) && isStackable(coupon))
|
|
39
|
+
.reduce((acc, coupon) => acc + (coupon as FixedPercentageCoupon).percentage, 0) * (total - stackedFixedDiscount)
|
|
40
|
+
// Sum all stackable discounts
|
|
41
|
+
const stackedDiscount = stackedFixedDiscount + stackedPercentageDiscount
|
|
42
|
+
|
|
43
|
+
// Find the best coupon(s) to apply
|
|
44
|
+
const maxDiscount = Math.max(
|
|
45
|
+
singularFixedDiscount,
|
|
46
|
+
singularPercentageDiscount,
|
|
47
|
+
stackedDiscount,
|
|
48
|
+
0,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
// Ensure discount is not more than the total
|
|
52
|
+
const amount = Math.min(maxDiscount, total)
|
|
53
|
+
|
|
54
|
+
// Return single discount payload
|
|
55
|
+
return {
|
|
56
|
+
amount, schema: DiscountSchema, currency: 'USD',
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './applyCoupons.ts'
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Hash } from '@xylabs/hex'
|
|
2
|
+
import type { DivinerInstance } from '@xyo-network/diviner-model'
|
|
3
|
+
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
4
|
+
import type { Payload } from '@xyo-network/payload-model'
|
|
5
|
+
import type {
|
|
6
|
+
Discount, EscrowTerms, Invoice, Payment, Subtotal, Total,
|
|
7
|
+
} from '@xyo-network/payment-payload-plugins'
|
|
8
|
+
import {
|
|
9
|
+
isDiscount, isSubtotal, isTotal, PaymentSchema,
|
|
10
|
+
} from '@xyo-network/payment-payload-plugins'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validates the escrow terms to ensure they are valid for a purchase
|
|
14
|
+
* @returns A payment if the terms are valid for a purchase, undefined otherwise
|
|
15
|
+
*/
|
|
16
|
+
export const getInvoiceForEscrow = async (
|
|
17
|
+
terms: EscrowTerms,
|
|
18
|
+
dataHashMap: Record<Hash, Payload>,
|
|
19
|
+
paymentTotalDiviner: DivinerInstance,
|
|
20
|
+
): Promise<Invoice | undefined> => {
|
|
21
|
+
const payloads = Object.values(dataHashMap)
|
|
22
|
+
const results = await paymentTotalDiviner.divine([terms, ...payloads])
|
|
23
|
+
const subtotal = results.find(isSubtotal) as Subtotal | undefined
|
|
24
|
+
const discount = results.find(isDiscount) as Discount | undefined
|
|
25
|
+
const total = results.find(isTotal) as Total | undefined
|
|
26
|
+
if (!subtotal || !total) return undefined
|
|
27
|
+
const { amount, currency } = total
|
|
28
|
+
if (currency !== 'USD') return undefined
|
|
29
|
+
const sources = await getSources(terms, subtotal, total, discount)
|
|
30
|
+
const payment: Payment = {
|
|
31
|
+
amount, currency, schema: PaymentSchema, sources,
|
|
32
|
+
}
|
|
33
|
+
return discount ? [subtotal, total, payment, discount] : [subtotal, total, payment]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const getSources = async (terms: EscrowTerms, subtotal: Subtotal, total: Total, discount?: Discount): Promise<Hash[]> => {
|
|
37
|
+
const sources = discount ? [terms, subtotal, total, discount] : [terms, subtotal, total]
|
|
38
|
+
return await Promise.all(sources.map(p => PayloadBuilder.dataHash(p)))
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getInvoiceForEscrow.ts'
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { AbstractDiviner } from '@xyo-network/diviner-abstract'
|
|
2
|
+
import { HashLeaseEstimate, isHashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
|
|
3
|
+
import { DivinerInstance, DivinerModuleEventData } from '@xyo-network/diviner-model'
|
|
4
|
+
import { creatableModule } from '@xyo-network/module-model'
|
|
5
|
+
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
6
|
+
import { Payload } from '@xyo-network/payload-model'
|
|
7
|
+
import {
|
|
8
|
+
EscrowTerms, isEscrowTerms, PaymentSubtotalDivinerConfigSchema, PaymentSubtotalDivinerParams, Subtotal, SubtotalSchema,
|
|
9
|
+
} from '@xyo-network/payment-payload-plugins'
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
appraisalValidators, termsValidators, ValidEscrowTerms,
|
|
13
|
+
} from './lib/index.ts'
|
|
14
|
+
|
|
15
|
+
const currency = 'USD'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Escrow terms that contain all the valid fields for calculating a subtotal
|
|
19
|
+
*/
|
|
20
|
+
export type PaymentSubtotalDivinerInputType = EscrowTerms | HashLeaseEstimate | Payload
|
|
21
|
+
|
|
22
|
+
@creatableModule()
|
|
23
|
+
export class PaymentSubtotalDiviner<
|
|
24
|
+
TParams extends PaymentSubtotalDivinerParams = PaymentSubtotalDivinerParams,
|
|
25
|
+
TIn extends PaymentSubtotalDivinerInputType = PaymentSubtotalDivinerInputType,
|
|
26
|
+
TOut extends Subtotal = Subtotal,
|
|
27
|
+
TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<
|
|
28
|
+
DivinerInstance<TParams, TIn, TOut>,
|
|
29
|
+
TIn,
|
|
30
|
+
TOut
|
|
31
|
+
>,
|
|
32
|
+
> extends AbstractDiviner<TParams, TIn, TOut, TEventData> {
|
|
33
|
+
static override configSchemas = [PaymentSubtotalDivinerConfigSchema]
|
|
34
|
+
static override defaultConfigSchema = PaymentSubtotalDivinerConfigSchema
|
|
35
|
+
|
|
36
|
+
protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {
|
|
37
|
+
// Find the escrow terms
|
|
38
|
+
const terms = payloads.find(isEscrowTerms) as EscrowTerms | undefined
|
|
39
|
+
if (!terms) return []
|
|
40
|
+
|
|
41
|
+
// Run all terms validations
|
|
42
|
+
if (!termsValidators.every(validator => validator(terms))) return []
|
|
43
|
+
const validTerms = terms as ValidEscrowTerms
|
|
44
|
+
|
|
45
|
+
// Retrieve all appraisals from terms
|
|
46
|
+
const hashMap = await PayloadBuilder.toAllHashMap(payloads)
|
|
47
|
+
const appraisals = validTerms.appraisals.map(appraisal => hashMap[appraisal]).filter(isHashLeaseEstimate) as unknown as HashLeaseEstimate[]
|
|
48
|
+
|
|
49
|
+
// Ensure all appraisals are present
|
|
50
|
+
if (appraisals.length !== validTerms.appraisals.length) return []
|
|
51
|
+
|
|
52
|
+
// Run all appraisal validations
|
|
53
|
+
if (!appraisalValidators.every(validator => validator(appraisals))) return []
|
|
54
|
+
const amount = calculateSubtotal(appraisals)
|
|
55
|
+
const sources = [await PayloadBuilder.dataHash(validTerms), ...validTerms.appraisals]
|
|
56
|
+
return [{
|
|
57
|
+
amount, currency, schema: SubtotalSchema, sources,
|
|
58
|
+
}] as TOut[]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// TODO: Add support for other currencies
|
|
63
|
+
const calculateSubtotal = (appraisals: HashLeaseEstimate[]): number => {
|
|
64
|
+
return appraisals.reduce((sum, appraisal) => sum + appraisal.price, 0)
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Diviner.ts'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
|
|
2
|
+
import { isIso4217CurrencyCode } from '@xyo-network/payment-payload-plugins'
|
|
3
|
+
|
|
4
|
+
import { validateDuration } from './durationValidators.ts'
|
|
5
|
+
|
|
6
|
+
const validateAppraisalAmount = (appraisals: HashLeaseEstimate[]): boolean => {
|
|
7
|
+
// Ensure all appraisals are numeric
|
|
8
|
+
if (appraisals.some(appraisal => typeof appraisal.price !== 'number')) return false
|
|
9
|
+
// Ensure all appraisals are positive numbers
|
|
10
|
+
if (appraisals.some(appraisal => appraisal.price < 0)) return false
|
|
11
|
+
return true
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const validateAppraisalCurrency = (appraisals: HashLeaseEstimate[]): boolean => {
|
|
15
|
+
// NOTE: Only supporting USD for now, the remaining checks are for future-proofing.
|
|
16
|
+
if (!appraisals.every(appraisal => appraisal.currency == 'USD')) return false
|
|
17
|
+
|
|
18
|
+
// Check every object in the array to ensure they all are in a supported currency.
|
|
19
|
+
if (!appraisals.every(appraisal => isIso4217CurrencyCode(appraisal.currency))) return false
|
|
20
|
+
|
|
21
|
+
return true
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const validateAppraisalConsistentCurrency = (appraisals: HashLeaseEstimate[]): boolean => {
|
|
25
|
+
// Check if the array is empty or contains only one element, no need to compare.
|
|
26
|
+
if (appraisals.length <= 1) return true
|
|
27
|
+
|
|
28
|
+
// Get the currency of the first element to compare with others.
|
|
29
|
+
const { currency } = appraisals[0]
|
|
30
|
+
if (!currency) return false
|
|
31
|
+
|
|
32
|
+
// Check every object in the array to ensure they all have the same currency.
|
|
33
|
+
if (!appraisals.every(item => item.currency === currency)) return false
|
|
34
|
+
|
|
35
|
+
return true
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const validateAppraisalWindow = (appraisals: HashLeaseEstimate[]): boolean => appraisals.every(validateDuration)
|
|
39
|
+
|
|
40
|
+
export const appraisalValidators = [
|
|
41
|
+
validateAppraisalAmount,
|
|
42
|
+
validateAppraisalCurrency,
|
|
43
|
+
validateAppraisalConsistentCurrency,
|
|
44
|
+
validateAppraisalWindow,
|
|
45
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DurationFields } from '@xyo-network/xns-record-payload-plugins'
|
|
2
|
+
|
|
3
|
+
const FIVE_MINUTES = 1000 * 60 * 5
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Validates that the current time is within the duration window, within a configurable a buffer
|
|
7
|
+
* @param value The duration value
|
|
8
|
+
* @param windowMs The window in milliseconds to allow for a buffer
|
|
9
|
+
* @returns True if the duration is valid, false otherwise
|
|
10
|
+
*/
|
|
11
|
+
export const validateDuration = (value: Partial<DurationFields>, windowMs = FIVE_MINUTES): boolean => {
|
|
12
|
+
const now = Date.now()
|
|
13
|
+
if (!value.nbf || value.nbf > now) return false
|
|
14
|
+
// If already expired (include for a 5 minute buffer to allow for a reasonable
|
|
15
|
+
// minimum amount of time for the transaction to be processed)
|
|
16
|
+
if (!value.exp || value.exp - now < windowMs) return false
|
|
17
|
+
return true
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Hash } from '@xylabs/hex'
|
|
2
|
+
import type { EscrowTerms } from '@xyo-network/payment-payload-plugins'
|
|
3
|
+
|
|
4
|
+
import { validateDuration } from './durationValidators.ts'
|
|
5
|
+
|
|
6
|
+
export type ValidEscrowTerms = Required<EscrowTerms>
|
|
7
|
+
|
|
8
|
+
const validateTermsAppraisals = (terms: EscrowTerms): terms is Required<EscrowTerms & { appraisals: Hash[] }> => {
|
|
9
|
+
if (!terms.appraisals) return false
|
|
10
|
+
if (terms.appraisals.length === 0) return false
|
|
11
|
+
return true
|
|
12
|
+
}
|
|
13
|
+
const validateTermsWindow = (terms: EscrowTerms): boolean => validateDuration(terms)
|
|
14
|
+
|
|
15
|
+
export const termsValidators = [
|
|
16
|
+
validateTermsAppraisals,
|
|
17
|
+
validateTermsWindow,
|
|
18
|
+
]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { assertEx } from '@xylabs/assert'
|
|
2
|
+
import { Hash } from '@xylabs/hex'
|
|
3
|
+
import { AbstractDiviner } from '@xyo-network/diviner-abstract'
|
|
4
|
+
import {
|
|
5
|
+
asDivinerInstance, DivinerInstance, DivinerModuleEventData,
|
|
6
|
+
} from '@xyo-network/diviner-model'
|
|
7
|
+
import { creatableModule } from '@xyo-network/module-model'
|
|
8
|
+
import {
|
|
9
|
+
Discount,
|
|
10
|
+
isDiscountWithMeta,
|
|
11
|
+
isSubtotalWithMeta,
|
|
12
|
+
PaymentTotalDivinerConfigSchema, PaymentTotalDivinerParams, Subtotal, Total, TotalSchema,
|
|
13
|
+
} from '@xyo-network/payment-payload-plugins'
|
|
14
|
+
|
|
15
|
+
import { PaymentDiscountDiviner, PaymentDiscountDivinerInputType } from '../Discount/index.ts'
|
|
16
|
+
import { PaymentSubtotalDiviner, PaymentSubtotalDivinerInputType } from '../Subtotal/index.ts'
|
|
17
|
+
|
|
18
|
+
type InputType = PaymentDiscountDivinerInputType | PaymentSubtotalDivinerInputType
|
|
19
|
+
type OutputType = Subtotal | Discount | Total
|
|
20
|
+
|
|
21
|
+
@creatableModule()
|
|
22
|
+
export class PaymentTotalDiviner<
|
|
23
|
+
TParams extends PaymentTotalDivinerParams = PaymentTotalDivinerParams,
|
|
24
|
+
TIn extends InputType = InputType,
|
|
25
|
+
TOut extends OutputType = OutputType,
|
|
26
|
+
TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<
|
|
27
|
+
DivinerInstance<TParams, TIn, TOut>,
|
|
28
|
+
TIn,
|
|
29
|
+
TOut
|
|
30
|
+
>,
|
|
31
|
+
> extends AbstractDiviner<TParams, TIn, TOut, TEventData> {
|
|
32
|
+
static override configSchemas = [PaymentTotalDivinerConfigSchema]
|
|
33
|
+
static override defaultConfigSchema: PaymentTotalDivinerConfigSchema = PaymentTotalDivinerConfigSchema
|
|
34
|
+
|
|
35
|
+
protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {
|
|
36
|
+
const subtotalDiviner = await this.getPaymentSubtotalDiviner()
|
|
37
|
+
const subtotalResult = await subtotalDiviner.divine(payloads)
|
|
38
|
+
const subtotal = subtotalResult.find(isSubtotalWithMeta)
|
|
39
|
+
if (!subtotal) return []
|
|
40
|
+
const discountDiviner = await this.getPaymentDiscountsDiviner()
|
|
41
|
+
const discountResult = await discountDiviner.divine(payloads)
|
|
42
|
+
const discount = discountResult.find(isDiscountWithMeta)
|
|
43
|
+
if (!discount) return []
|
|
44
|
+
const { currency: subtotalCurrency } = subtotal
|
|
45
|
+
const { currency: discountCurrency } = discount
|
|
46
|
+
assertEx(subtotalCurrency === discountCurrency, () => `Subtotal currency ${subtotalCurrency} does not match discount currency ${discountCurrency}`)
|
|
47
|
+
const amount = Math.max(0, subtotal.amount - discount.amount)
|
|
48
|
+
const currency = subtotalCurrency
|
|
49
|
+
const sources = [subtotal.$hash, discount.$hash] as Hash[]
|
|
50
|
+
const total: Total = {
|
|
51
|
+
amount, currency, sources, schema: TotalSchema,
|
|
52
|
+
}
|
|
53
|
+
return [subtotal, discount, total] as TOut[]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected async getPaymentDiscountsDiviner(): Promise<PaymentDiscountDiviner> {
|
|
57
|
+
const name = assertEx(this.config.paymentDiscountDiviner, () => 'Missing paymentDiscountDiviner in config')
|
|
58
|
+
const mod = assertEx(await this.resolve(name), () => `Error resolving paymentDiscountDiviner: ${name}`)
|
|
59
|
+
return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`) as PaymentDiscountDiviner
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
protected async getPaymentSubtotalDiviner(): Promise<PaymentSubtotalDiviner> {
|
|
63
|
+
const name = assertEx(this.config.paymentSubtotalDiviner, () => 'Missing paymentSubtotalDiviner in config')
|
|
64
|
+
const mod = assertEx(await this.resolve(name), () => `Error resolving paymentSubtotalDiviner: ${name}`)
|
|
65
|
+
return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`) as PaymentSubtotalDiviner
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Diviner.ts'
|
package/src/index.ts
ADDED
package/typedoc.json
ADDED
package/xy.config.ts
ADDED