@mj-biz-apps/orders-core-entities-server 0.0.1 → 5.2.0
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 +183 -0
- package/README.md +141 -2
- package/dist/AccountingBridge.d.ts +65 -0
- package/dist/AccountingBridge.d.ts.map +1 -0
- package/dist/AccountingBridge.js +102 -0
- package/dist/AccountingBridge.js.map +1 -0
- package/dist/AdvanceOrderStateOperation.d.ts +80 -0
- package/dist/AdvanceOrderStateOperation.d.ts.map +1 -0
- package/dist/AdvanceOrderStateOperation.js +267 -0
- package/dist/AdvanceOrderStateOperation.js.map +1 -0
- package/dist/ApplyAccountCreditOperation.d.ts +97 -0
- package/dist/ApplyAccountCreditOperation.d.ts.map +1 -0
- package/dist/ApplyAccountCreditOperation.js +275 -0
- package/dist/ApplyAccountCreditOperation.js.map +1 -0
- package/dist/BaseDeliveryChannel.d.ts +106 -0
- package/dist/BaseDeliveryChannel.d.ts.map +1 -0
- package/dist/BaseDeliveryChannel.js +36 -0
- package/dist/BaseDeliveryChannel.js.map +1 -0
- package/dist/BasePaymentProvider.d.ts +239 -0
- package/dist/BasePaymentProvider.d.ts.map +1 -0
- package/dist/BasePaymentProvider.js +91 -0
- package/dist/BasePaymentProvider.js.map +1 -0
- package/dist/BundleBehavior.d.ts +139 -0
- package/dist/BundleBehavior.d.ts.map +1 -0
- package/dist/BundleBehavior.js +173 -0
- package/dist/BundleBehavior.js.map +1 -0
- package/dist/BundleEngine.d.ts +60 -0
- package/dist/BundleEngine.d.ts.map +1 -0
- package/dist/BundleEngine.js +197 -0
- package/dist/BundleEngine.js.map +1 -0
- package/dist/CancelSubscriptionOperation.d.ts +98 -0
- package/dist/CancelSubscriptionOperation.d.ts.map +1 -0
- package/dist/CancelSubscriptionOperation.js +317 -0
- package/dist/CancelSubscriptionOperation.js.map +1 -0
- package/dist/CapturePaymentOperation.d.ts +62 -0
- package/dist/CapturePaymentOperation.d.ts.map +1 -0
- package/dist/CapturePaymentOperation.js +463 -0
- package/dist/CapturePaymentOperation.js.map +1 -0
- package/dist/CheckEntitlementOperation.d.ts +27 -0
- package/dist/CheckEntitlementOperation.d.ts.map +1 -0
- package/dist/CheckEntitlementOperation.js +45 -0
- package/dist/CheckEntitlementOperation.js.map +1 -0
- package/dist/CheckoutSessionService.d.ts +258 -0
- package/dist/CheckoutSessionService.d.ts.map +1 -0
- package/dist/CheckoutSessionService.js +1557 -0
- package/dist/CheckoutSessionService.js.map +1 -0
- package/dist/DeliveryBehavior.d.ts +121 -0
- package/dist/DeliveryBehavior.d.ts.map +1 -0
- package/dist/DeliveryBehavior.js +145 -0
- package/dist/DeliveryBehavior.js.map +1 -0
- package/dist/DeliveryRecipientResolver.d.ts +38 -0
- package/dist/DeliveryRecipientResolver.d.ts.map +1 -0
- package/dist/DeliveryRecipientResolver.js +93 -0
- package/dist/DeliveryRecipientResolver.js.map +1 -0
- package/dist/DeliveryResolver.d.ts +14 -0
- package/dist/DeliveryResolver.d.ts.map +1 -0
- package/dist/DeliveryResolver.js +45 -0
- package/dist/DeliveryResolver.js.map +1 -0
- package/dist/EmailDeliveryChannel.d.ts +31 -0
- package/dist/EmailDeliveryChannel.d.ts.map +1 -0
- package/dist/EmailDeliveryChannel.js +158 -0
- package/dist/EmailDeliveryChannel.js.map +1 -0
- package/dist/EntitlementBehavior.d.ts +235 -0
- package/dist/EntitlementBehavior.d.ts.map +1 -0
- package/dist/EntitlementBehavior.js +330 -0
- package/dist/EntitlementBehavior.js.map +1 -0
- package/dist/EntitlementEngine.d.ts +97 -0
- package/dist/EntitlementEngine.d.ts.map +1 -0
- package/dist/EntitlementEngine.js +338 -0
- package/dist/EntitlementEngine.js.map +1 -0
- package/dist/EntitlementGrantClaimDriver.d.ts +42 -0
- package/dist/EntitlementGrantClaimDriver.d.ts.map +1 -0
- package/dist/EntitlementGrantClaimDriver.js +158 -0
- package/dist/EntitlementGrantClaimDriver.js.map +1 -0
- package/dist/EntitlementRead.d.ts +82 -0
- package/dist/EntitlementRead.d.ts.map +1 -0
- package/dist/EntitlementRead.js +368 -0
- package/dist/EntitlementRead.js.map +1 -0
- package/dist/FulfillOrderLinesOperation.d.ts +34 -0
- package/dist/FulfillOrderLinesOperation.d.ts.map +1 -0
- package/dist/FulfillOrderLinesOperation.js +208 -0
- package/dist/FulfillOrderLinesOperation.js.map +1 -0
- package/dist/FulfillmentBehavior.d.ts +101 -0
- package/dist/FulfillmentBehavior.d.ts.map +1 -0
- package/dist/FulfillmentBehavior.js +145 -0
- package/dist/FulfillmentBehavior.js.map +1 -0
- package/dist/GLAccountResolver.d.ts +123 -0
- package/dist/GLAccountResolver.d.ts.map +1 -0
- package/dist/GLAccountResolver.js +175 -0
- package/dist/GLAccountResolver.js.map +1 -0
- package/dist/GetFulfillmentQueueOperation.d.ts +35 -0
- package/dist/GetFulfillmentQueueOperation.d.ts.map +1 -0
- package/dist/GetFulfillmentQueueOperation.js +221 -0
- package/dist/GetFulfillmentQueueOperation.js.map +1 -0
- package/dist/GetOverdueWorklistOperation.d.ts +41 -0
- package/dist/GetOverdueWorklistOperation.d.ts.map +1 -0
- package/dist/GetOverdueWorklistOperation.js +210 -0
- package/dist/GetOverdueWorklistOperation.js.map +1 -0
- package/dist/GiftCardBehavior.d.ts +97 -0
- package/dist/GiftCardBehavior.d.ts.map +1 -0
- package/dist/GiftCardBehavior.js +121 -0
- package/dist/GiftCardBehavior.js.map +1 -0
- package/dist/GiftCardEngine.d.ts +59 -0
- package/dist/GiftCardEngine.d.ts.map +1 -0
- package/dist/GiftCardEngine.js +197 -0
- package/dist/GiftCardEngine.js.map +1 -0
- package/dist/GuestOrderClaimDriver.d.ts +36 -0
- package/dist/GuestOrderClaimDriver.d.ts.map +1 -0
- package/dist/GuestOrderClaimDriver.js +161 -0
- package/dist/GuestOrderClaimDriver.js.map +1 -0
- package/dist/InvoiceBehavior.d.ts +394 -0
- package/dist/InvoiceBehavior.d.ts.map +1 -0
- package/dist/InvoiceBehavior.js +496 -0
- package/dist/InvoiceBehavior.js.map +1 -0
- package/dist/InvoiceBuilder.d.ts +48 -0
- package/dist/InvoiceBuilder.d.ts.map +1 -0
- package/dist/InvoiceBuilder.js +352 -0
- package/dist/InvoiceBuilder.js.map +1 -0
- package/dist/InvoiceDisplay.d.ts +96 -0
- package/dist/InvoiceDisplay.d.ts.map +1 -0
- package/dist/InvoiceDisplay.js +121 -0
- package/dist/InvoiceDisplay.js.map +1 -0
- package/dist/ListEntitlementsOperation.d.ts +21 -0
- package/dist/ListEntitlementsOperation.d.ts.map +1 -0
- package/dist/ListEntitlementsOperation.js +39 -0
- package/dist/ListEntitlementsOperation.js.map +1 -0
- package/dist/ManualPaymentProvider.d.ts +19 -0
- package/dist/ManualPaymentProvider.d.ts.map +1 -0
- package/dist/ManualPaymentProvider.js +92 -0
- package/dist/ManualPaymentProvider.js.map +1 -0
- package/dist/OrderEntityServer.d.ts +542 -0
- package/dist/OrderEntityServer.d.ts.map +1 -0
- package/dist/OrderEntityServer.js +2100 -0
- package/dist/OrderEntityServer.js.map +1 -0
- package/dist/OrderJournalEntryFactory.d.ts +140 -0
- package/dist/OrderJournalEntryFactory.d.ts.map +1 -0
- package/dist/OrderJournalEntryFactory.js +466 -0
- package/dist/OrderJournalEntryFactory.js.map +1 -0
- package/dist/OrderLineEntityServer.d.ts +90 -0
- package/dist/OrderLineEntityServer.d.ts.map +1 -0
- package/dist/OrderLineEntityServer.js +260 -0
- package/dist/OrderLineEntityServer.js.map +1 -0
- package/dist/OrdersSettings.d.ts +36 -0
- package/dist/OrdersSettings.d.ts.map +1 -0
- package/dist/OrdersSettings.js +147 -0
- package/dist/OrdersSettings.js.map +1 -0
- package/dist/PaymentAllocationFactory.d.ts +128 -0
- package/dist/PaymentAllocationFactory.d.ts.map +1 -0
- package/dist/PaymentAllocationFactory.js +235 -0
- package/dist/PaymentAllocationFactory.js.map +1 -0
- package/dist/PaymentHeaderEntityServer.d.ts +180 -0
- package/dist/PaymentHeaderEntityServer.d.ts.map +1 -0
- package/dist/PaymentHeaderEntityServer.js +656 -0
- package/dist/PaymentHeaderEntityServer.js.map +1 -0
- package/dist/PaymentIntentService.d.ts +101 -0
- package/dist/PaymentIntentService.d.ts.map +1 -0
- package/dist/PaymentIntentService.js +150 -0
- package/dist/PaymentIntentService.js.map +1 -0
- package/dist/PaymentJournalEntryFactory.d.ts +99 -0
- package/dist/PaymentJournalEntryFactory.d.ts.map +1 -0
- package/dist/PaymentJournalEntryFactory.js +127 -0
- package/dist/PaymentJournalEntryFactory.js.map +1 -0
- package/dist/PaymentLineEntityServer.d.ts +73 -0
- package/dist/PaymentLineEntityServer.d.ts.map +1 -0
- package/dist/PaymentLineEntityServer.js +303 -0
- package/dist/PaymentLineEntityServer.js.map +1 -0
- package/dist/PaymentProviderBehavior.d.ts +222 -0
- package/dist/PaymentProviderBehavior.d.ts.map +1 -0
- package/dist/PaymentProviderBehavior.js +368 -0
- package/dist/PaymentProviderBehavior.js.map +1 -0
- package/dist/PaymentProviderResolver.d.ts +84 -0
- package/dist/PaymentProviderResolver.d.ts.map +1 -0
- package/dist/PaymentProviderResolver.js +220 -0
- package/dist/PaymentProviderResolver.js.map +1 -0
- package/dist/PaymentReversalFactory.d.ts +107 -0
- package/dist/PaymentReversalFactory.d.ts.map +1 -0
- package/dist/PaymentReversalFactory.js +174 -0
- package/dist/PaymentReversalFactory.js.map +1 -0
- package/dist/PaymentSettlement.d.ts +56 -0
- package/dist/PaymentSettlement.d.ts.map +1 -0
- package/dist/PaymentSettlement.js +243 -0
- package/dist/PaymentSettlement.js.map +1 -0
- package/dist/PaymentTermsBehavior.d.ts +109 -0
- package/dist/PaymentTermsBehavior.d.ts.map +1 -0
- package/dist/PaymentTermsBehavior.js +172 -0
- package/dist/PaymentTermsBehavior.js.map +1 -0
- package/dist/PaymentWebhookHandler.d.ts +103 -0
- package/dist/PaymentWebhookHandler.d.ts.map +1 -0
- package/dist/PaymentWebhookHandler.js +246 -0
- package/dist/PaymentWebhookHandler.js.map +1 -0
- package/dist/PreviewPriceOperation.d.ts +62 -0
- package/dist/PreviewPriceOperation.d.ts.map +1 -0
- package/dist/PreviewPriceOperation.js +161 -0
- package/dist/PreviewPriceOperation.js.map +1 -0
- package/dist/PriceOrderOperation.d.ts +93 -0
- package/dist/PriceOrderOperation.d.ts.map +1 -0
- package/dist/PriceOrderOperation.js +146 -0
- package/dist/PriceOrderOperation.js.map +1 -0
- package/dist/ProductPriceEntityServer.d.ts +34 -0
- package/dist/ProductPriceEntityServer.d.ts.map +1 -0
- package/dist/ProductPriceEntityServer.js +97 -0
- package/dist/ProductPriceEntityServer.js.map +1 -0
- package/dist/RefundPaymentOperation.d.ts +61 -0
- package/dist/RefundPaymentOperation.d.ts.map +1 -0
- package/dist/RefundPaymentOperation.js +177 -0
- package/dist/RefundPaymentOperation.js.map +1 -0
- package/dist/RevenueRecognition.d.ts +76 -0
- package/dist/RevenueRecognition.d.ts.map +1 -0
- package/dist/RevenueRecognition.js +133 -0
- package/dist/RevenueRecognition.js.map +1 -0
- package/dist/ReversalBehavior.d.ts +82 -0
- package/dist/ReversalBehavior.d.ts.map +1 -0
- package/dist/ReversalBehavior.js +100 -0
- package/dist/ReversalBehavior.js.map +1 -0
- package/dist/ReversalResolver.d.ts +37 -0
- package/dist/ReversalResolver.d.ts.map +1 -0
- package/dist/ReversalResolver.js +96 -0
- package/dist/ReversalResolver.js.map +1 -0
- package/dist/SpawnRenewalsOperation.d.ts +109 -0
- package/dist/SpawnRenewalsOperation.d.ts.map +1 -0
- package/dist/SpawnRenewalsOperation.js +295 -0
- package/dist/SpawnRenewalsOperation.js.map +1 -0
- package/dist/StoredValuePaymentProvider.d.ts +52 -0
- package/dist/StoredValuePaymentProvider.d.ts.map +1 -0
- package/dist/StoredValuePaymentProvider.js +205 -0
- package/dist/StoredValuePaymentProvider.js.map +1 -0
- package/dist/StripeACHPaymentProvider.d.ts +50 -0
- package/dist/StripeACHPaymentProvider.d.ts.map +1 -0
- package/dist/StripeACHPaymentProvider.js +211 -0
- package/dist/StripeACHPaymentProvider.js.map +1 -0
- package/dist/StripePaymentProvider.d.ts +83 -0
- package/dist/StripePaymentProvider.d.ts.map +1 -0
- package/dist/StripePaymentProvider.js +442 -0
- package/dist/StripePaymentProvider.js.map +1 -0
- package/dist/SubscriptionBehavior.d.ts +197 -0
- package/dist/SubscriptionBehavior.d.ts.map +1 -0
- package/dist/SubscriptionBehavior.js +415 -0
- package/dist/SubscriptionBehavior.js.map +1 -0
- package/dist/checkoutCaptureAlert.d.ts +16 -0
- package/dist/checkoutCaptureAlert.d.ts.map +1 -0
- package/dist/checkoutCaptureAlert.js +55 -0
- package/dist/checkoutCaptureAlert.js.map +1 -0
- package/dist/checkoutCaptureRetry.d.ts +27 -0
- package/dist/checkoutCaptureRetry.d.ts.map +1 -0
- package/dist/checkoutCaptureRetry.js +50 -0
- package/dist/checkoutCaptureRetry.js.map +1 -0
- package/dist/claimDriverHelpers.d.ts +15 -0
- package/dist/claimDriverHelpers.d.ts.map +1 -0
- package/dist/claimDriverHelpers.js +34 -0
- package/dist/claimDriverHelpers.js.map +1 -0
- package/dist/entity-names.d.ts +15 -0
- package/dist/entity-names.d.ts.map +1 -0
- package/dist/entity-names.js +15 -0
- package/dist/entity-names.js.map +1 -0
- package/dist/identityClaimContracts.d.ts +118 -0
- package/dist/identityClaimContracts.d.ts.map +1 -0
- package/dist/identityClaimContracts.js +58 -0
- package/dist/identityClaimContracts.js.map +1 -0
- package/dist/index.d.ts +126 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -0
- package/dist/sql-guards.d.ts +78 -0
- package/dist/sql-guards.d.ts.map +1 -0
- package/dist/sql-guards.js +115 -0
- package/dist/sql-guards.js.map +1 -0
- package/package.json +50 -5
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BaseDeliveryChannel, type DeliverableDocument, type DeliveryAddressing, type DeliveryContext, type DeliveryResult } from './BaseDeliveryChannel.js';
|
|
2
|
+
export declare class EmailDeliveryChannel extends BaseDeliveryChannel {
|
|
3
|
+
/**
|
|
4
|
+
* Which MJ communication provider to send through.
|
|
5
|
+
*
|
|
6
|
+
* A GETTER, NOT AN ENV READ. This package's tsconfig sets `"types": []` — it has no Node globals
|
|
7
|
+
* by design, which is also why the signature code uses Web Crypto rather than `node:crypto`. So a
|
|
8
|
+
* deployment that sends through Microsoft Graph subclasses this and overrides the getter, and its
|
|
9
|
+
* `@RegisterClass(BaseDeliveryChannel, 'Email')` wins by load-order priority. That is the same
|
|
10
|
+
* escape hatch the payment drivers offer, and it keeps the choice in code somebody can read rather
|
|
11
|
+
* than in an environment variable nobody can find.
|
|
12
|
+
*/
|
|
13
|
+
protected get ProviderName(): string;
|
|
14
|
+
Deliver(document: DeliverableDocument, addressing: DeliveryAddressing, context: DeliveryContext): Promise<DeliveryResult>;
|
|
15
|
+
/**
|
|
16
|
+
* Our vocabulary, translated into MJ's `Message`.
|
|
17
|
+
*
|
|
18
|
+
* `From` IS LEFT UNSET WHEN THE CALLER DID NOT SUPPLY ONE, rather than defaulted to something
|
|
19
|
+
* plausible. MJ's provider resolves its own configured sender, and a guess here — a no-reply
|
|
20
|
+
* address this app invented — would either be rejected by the provider's domain authentication or,
|
|
21
|
+
* worse, accepted and send the company's invoices from an address nobody monitors for replies.
|
|
22
|
+
*
|
|
23
|
+
* BOTH BODIES ARE SET when the caller supplied a plain-text alternative. An HTML-only message is
|
|
24
|
+
* one of the strongest spam signals there is, and an invoice landing in a junk folder is
|
|
25
|
+
* indistinguishable from one that was never sent.
|
|
26
|
+
*/
|
|
27
|
+
private buildMessage;
|
|
28
|
+
}
|
|
29
|
+
/** Tree-shaking anchor — call from the server bootstrap so @RegisterClass is retained. */
|
|
30
|
+
export declare function LoadEmailDeliveryChannel(): void;
|
|
31
|
+
//# sourceMappingURL=EmailDeliveryChannel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailDeliveryChannel.d.ts","sourceRoot":"","sources":["../src/EmailDeliveryChannel.ts"],"names":[],"mappings":"AAqCA,OAAO,EACH,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,cAAc,EACtB,MAAM,0BAA0B,CAAC;AAclC,qBACa,oBAAqB,SAAQ,mBAAmB;IACzD;;;;;;;;;OASG;IACH,SAAS,KAAK,YAAY,IAAI,MAAM,CAEnC;IAEqB,OAAO,CACzB,QAAQ,EAAE,mBAAmB,EAC7B,UAAU,EAAE,kBAAkB,EAC9B,OAAO,EAAE,eAAe,GACzB,OAAO,CAAC,cAAc,CAAC;IAiE1B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,YAAY;CAkBvB;AAED,0FAA0F;AAC1F,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* EmailDeliveryChannel — sending a rendered document, over MJ's communication framework.
|
|
9
|
+
*
|
|
10
|
+
* THIS CLASS IS DELIBERATELY THIN, and the thinness is the design. MJ's `CommunicationEngine` already
|
|
11
|
+
* owns provider registration, credential resolution, template processing, dry-run preview, and — the
|
|
12
|
+
* one that matters most here — a persisted log row per message with its status and any error. Every
|
|
13
|
+
* one of those is a thing a hand-rolled mail path in this app would have had to grow, badly, over the
|
|
14
|
+
* following year. So this channel translates our vocabulary into MJ's and gets out of the way.
|
|
15
|
+
*
|
|
16
|
+
* THE LOG IS WHY THERE IS NO ORDERS-SIDE DELIVERY TABLE YET. `CommunicationEngine.SendSingleMessage`
|
|
17
|
+
* writes a `MJ: Communication Logs` row for every send, carrying the recipient, the body as sent, the
|
|
18
|
+
* status and the failure reason. That answers "was it sent, to whom, and did it work" today, without
|
|
19
|
+
* a schema change. What it does NOT answer is "has THIS ORDER been invoiced, and when" — that needs a
|
|
20
|
+
* row keyed by the order, and it is the deliberate next step rather than something to fake here by
|
|
21
|
+
* stuffing an order id into a log message.
|
|
22
|
+
*
|
|
23
|
+
* ONE MESSAGE PER RECIPIENT, NOT ONE MESSAGE WITH MANY RECIPIENTS. Two reasons, and the second is the
|
|
24
|
+
* one that decided it. A single message would expose every billing contact's address to all the
|
|
25
|
+
* others — a real disclosure when a customer's contacts span two organisations. And a partial failure
|
|
26
|
+
* on a multi-recipient send is unattributable: the provider reports one status for the message, so
|
|
27
|
+
* "delivered to two of three" is indistinguishable from "delivered", and nobody learns which contact
|
|
28
|
+
* did not get the bill.
|
|
29
|
+
*
|
|
30
|
+
* A PARTIAL SEND IS A FAILURE, reported with the addresses that DID work. The alternative — reporting
|
|
31
|
+
* success because at least one landed — is how an invoice quietly stops reaching the person who
|
|
32
|
+
* actually pays it while the send log stays green.
|
|
33
|
+
*
|
|
34
|
+
* CONNECTS TO:
|
|
35
|
+
* BASE: ./BaseDeliveryChannel.ts
|
|
36
|
+
* PURE: ./DeliveryBehavior.ts
|
|
37
|
+
* MJ: @memberjunction/communication-engine
|
|
38
|
+
* DOC: plans/archive/bizapps-orders-master.md §4.4
|
|
39
|
+
*/
|
|
40
|
+
import { LogError, LogStatus } from '@memberjunction/core';
|
|
41
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
42
|
+
import { CommunicationEngine } from '@memberjunction/communication-engine';
|
|
43
|
+
import { Message } from '@memberjunction/communication-types';
|
|
44
|
+
import { BaseDeliveryChannel, } from './BaseDeliveryChannel.js';
|
|
45
|
+
/**
|
|
46
|
+
* The MJ communication provider used when the app has not been told otherwise.
|
|
47
|
+
*
|
|
48
|
+
* SendGrid because it is the provider MJ ships an email implementation for and the one most
|
|
49
|
+
* deployments already configure. It is a constant rather than a hard-coded string in five places so
|
|
50
|
+
* a deployment that uses Microsoft Graph changes it here, and so this comment has somewhere to live.
|
|
51
|
+
*/
|
|
52
|
+
const DEFAULT_PROVIDER = 'SendGrid';
|
|
53
|
+
/** MJ's own name for the message type. Not ours to invent — it is looked up in MJ's metadata. */
|
|
54
|
+
const MESSAGE_TYPE = 'Email';
|
|
55
|
+
let EmailDeliveryChannel = class EmailDeliveryChannel extends BaseDeliveryChannel {
|
|
56
|
+
/**
|
|
57
|
+
* Which MJ communication provider to send through.
|
|
58
|
+
*
|
|
59
|
+
* A GETTER, NOT AN ENV READ. This package's tsconfig sets `"types": []` — it has no Node globals
|
|
60
|
+
* by design, which is also why the signature code uses Web Crypto rather than `node:crypto`. So a
|
|
61
|
+
* deployment that sends through Microsoft Graph subclasses this and overrides the getter, and its
|
|
62
|
+
* `@RegisterClass(BaseDeliveryChannel, 'Email')` wins by load-order priority. That is the same
|
|
63
|
+
* escape hatch the payment drivers offer, and it keeps the choice in code somebody can read rather
|
|
64
|
+
* than in an environment variable nobody can find.
|
|
65
|
+
*/
|
|
66
|
+
get ProviderName() {
|
|
67
|
+
return DEFAULT_PROVIDER;
|
|
68
|
+
}
|
|
69
|
+
async Deliver(document, addressing, context) {
|
|
70
|
+
const recipients = (addressing.To ?? []).filter((r) => (r.Address ?? '').trim());
|
|
71
|
+
if (!recipients.length) {
|
|
72
|
+
// A REFUSAL, not a throw: nothing is broken, there is simply nobody to send to. The caller
|
|
73
|
+
// should have asked `DecideDelivery` first, and this is the backstop for the one who did not.
|
|
74
|
+
return { Success: false, Delivered: [], Reason: 'no recipient address was supplied' };
|
|
75
|
+
}
|
|
76
|
+
const engine = CommunicationEngine.Instance;
|
|
77
|
+
await engine.Config(false, context.User, context.Provider);
|
|
78
|
+
const delivered = [];
|
|
79
|
+
const failures = [];
|
|
80
|
+
let providerMessageID;
|
|
81
|
+
for (const recipient of recipients) {
|
|
82
|
+
const address = recipient.Address.trim();
|
|
83
|
+
const message = this.buildMessage(document, addressing, address, recipient.FullName ?? undefined);
|
|
84
|
+
try {
|
|
85
|
+
const result = await engine.SendSingleMessage(this.ProviderName, MESSAGE_TYPE, message, undefined, context.PreviewOnly === true);
|
|
86
|
+
if (result?.Success) {
|
|
87
|
+
delivered.push(address);
|
|
88
|
+
providerMessageID ??= result.Message?.MessageType?.ID;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
failures.push(`${address}: ${result?.Error || 'the provider reported a failure with no reason'}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
// A FAULT — the provider was unreachable or threw. It is caught rather than propagated
|
|
96
|
+
// so one unreachable recipient does not abandon the rest, and it is recorded as a
|
|
97
|
+
// failure so the overall result cannot come back green.
|
|
98
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
99
|
+
LogError(`Delivering ${document.DocumentNumber} to ${address} threw: ${reason}`);
|
|
100
|
+
failures.push(`${address}: ${reason}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (failures.length) {
|
|
104
|
+
// Partial success is reported as failure WITH the addresses that worked, so a retry can
|
|
105
|
+
// skip them. Reporting success because one landed is how a bill quietly stops reaching the
|
|
106
|
+
// person who pays it.
|
|
107
|
+
return {
|
|
108
|
+
Success: false,
|
|
109
|
+
Delivered: delivered,
|
|
110
|
+
ProviderMessageID: providerMessageID,
|
|
111
|
+
Reason: `${document.DocumentNumber} reached ${delivered.length} of ${recipients.length} recipients. ` +
|
|
112
|
+
`Failures: ${failures.join('; ')}`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
LogStatus(`${document.Kind} ${document.DocumentNumber} ${context.PreviewOnly ? 'previewed for' : 'sent to'} ` +
|
|
116
|
+
`${delivered.join(', ')}.`);
|
|
117
|
+
return { Success: true, Delivered: delivered, ProviderMessageID: providerMessageID };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Our vocabulary, translated into MJ's `Message`.
|
|
121
|
+
*
|
|
122
|
+
* `From` IS LEFT UNSET WHEN THE CALLER DID NOT SUPPLY ONE, rather than defaulted to something
|
|
123
|
+
* plausible. MJ's provider resolves its own configured sender, and a guess here — a no-reply
|
|
124
|
+
* address this app invented — would either be rejected by the provider's domain authentication or,
|
|
125
|
+
* worse, accepted and send the company's invoices from an address nobody monitors for replies.
|
|
126
|
+
*
|
|
127
|
+
* BOTH BODIES ARE SET when the caller supplied a plain-text alternative. An HTML-only message is
|
|
128
|
+
* one of the strongest spam signals there is, and an invoice landing in a junk folder is
|
|
129
|
+
* indistinguishable from one that was never sent.
|
|
130
|
+
*/
|
|
131
|
+
buildMessage(document, addressing, address, fullName) {
|
|
132
|
+
const message = new Message();
|
|
133
|
+
message.To = address;
|
|
134
|
+
message.Subject = document.Subject;
|
|
135
|
+
message.HTMLBody = document.BodyHtml;
|
|
136
|
+
if (document.BodyPlain)
|
|
137
|
+
message.Body = document.BodyPlain;
|
|
138
|
+
if (addressing.From)
|
|
139
|
+
message.From = addressing.From;
|
|
140
|
+
if (addressing.FromName)
|
|
141
|
+
message.FromName = addressing.FromName;
|
|
142
|
+
if (addressing.CC?.length)
|
|
143
|
+
message.CCRecipients = [...addressing.CC];
|
|
144
|
+
if (addressing.BCC?.length)
|
|
145
|
+
message.BCCRecipients = [...addressing.BCC];
|
|
146
|
+
void fullName; // MJ's Message carries no per-recipient display name; kept for the seam's shape.
|
|
147
|
+
return message;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
EmailDeliveryChannel = __decorate([
|
|
151
|
+
RegisterClass(BaseDeliveryChannel, 'Email')
|
|
152
|
+
], EmailDeliveryChannel);
|
|
153
|
+
export { EmailDeliveryChannel };
|
|
154
|
+
/** Tree-shaking anchor — call from the server bootstrap so @RegisterClass is retained. */
|
|
155
|
+
export function LoadEmailDeliveryChannel() {
|
|
156
|
+
// intentionally empty
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=EmailDeliveryChannel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailDeliveryChannel.js","sourceRoot":"","sources":["../src/EmailDeliveryChannel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a purchase grants, and for how long — the arithmetic, with no database in sight.
|
|
3
|
+
*
|
|
4
|
+
* A `ProductEntitlement` is a TEMPLATE: this product confers this feature, access level, or resource
|
|
5
|
+
* quantity. An `EntitlementGrant` is the INSTANCE created when somebody buys it, carrying a
|
|
6
|
+
* beneficiary and a validity window. This module decides what that instance should look like.
|
|
7
|
+
*
|
|
8
|
+
* THREE SETTINGS, ONE WALK (D76). Timing, quantity and validity are all configurable per deployment,
|
|
9
|
+
* and all three resolve down the SAME chain taxability uses:
|
|
10
|
+
*
|
|
11
|
+
* product → its category → that category's ancestors → the product type
|
|
12
|
+
*
|
|
13
|
+
* Nullable at product and category so "ask my parent" is sayable; NOT NULL at the type so the walk
|
|
14
|
+
* always terminates with a real answer. Sharing the chain is deliberate rather than tidy: anyone who
|
|
15
|
+
* understands how taxability resolves already understands this, and the two cannot drift into
|
|
16
|
+
* disagreeing about what "the product's category tree" means.
|
|
17
|
+
*
|
|
18
|
+
* WHY VALIDITY IS DIFFERENT FROM THE OTHER TWO. It is read from the `ProductEntitlement` FIRST and
|
|
19
|
+
* from the walk only when the template is silent, because one product can grant two entitlements with
|
|
20
|
+
* different windows. A course might give perpetual access to the downloadable materials and ninety
|
|
21
|
+
* days in the discussion forum. A policy resolved purely from the product could not say that.
|
|
22
|
+
*
|
|
23
|
+
* THE NON-SUBSCRIPTION CASES ARE THE INTERESTING ONES. It is tempting to assume access follows a
|
|
24
|
+
* subscription term, because that is the case with the most moving parts. But the commonest grants
|
|
25
|
+
* have nothing to do with subscriptions at all: a digital download is good forever, and a ticket to
|
|
26
|
+
* an online event is good for the length of the event and not a minute longer.
|
|
27
|
+
*
|
|
28
|
+
* CONNECTS TO:
|
|
29
|
+
* SERVER: ./EntitlementEngine.ts (the lookups and the writes)
|
|
30
|
+
* CALLER: OrderEntityServer (grants are created inside the booking transaction)
|
|
31
|
+
* MIRROR: ./TaxResolver.ts — the same walk, for the same reason
|
|
32
|
+
* DOC: plans/archive/bizapps-orders-master.md D27, D76
|
|
33
|
+
*/
|
|
34
|
+
/** When access begins. */
|
|
35
|
+
export type GrantTiming = 'OnConfirm' | 'OnPaidInFull' | 'OnActivation';
|
|
36
|
+
/** How the template quantity relates to the line quantity. */
|
|
37
|
+
export type QuantityMode = 'PerUnit' | 'Flat';
|
|
38
|
+
/** How long access lasts. */
|
|
39
|
+
export type ValidityMode = 'Perpetual' | 'EventWindow' | 'FixedDuration' | 'SubscriptionTerm';
|
|
40
|
+
/** Where in the chain an answer came from. Recorded because "nobody said" differs from "it said no". */
|
|
41
|
+
export type PolicyLevel = 'ProductEntitlement' | 'Product' | 'ProductCategory' | 'ProductType';
|
|
42
|
+
export interface EntitlementPolicySource {
|
|
43
|
+
EntitlementGrantTiming: GrantTiming | null;
|
|
44
|
+
EntitlementQuantityMode: QuantityMode | null;
|
|
45
|
+
EntitlementValidityMode: ValidityMode | null;
|
|
46
|
+
}
|
|
47
|
+
/** One level of the category tree. Callers build these NEAREST FIRST. */
|
|
48
|
+
export interface PolicyCategoryLevel extends EntitlementPolicySource {
|
|
49
|
+
ID: string;
|
|
50
|
+
}
|
|
51
|
+
/** The type's answers are NOT NULL — this is what makes the walk terminate. */
|
|
52
|
+
export interface PolicyTypeDefaults {
|
|
53
|
+
DefaultEntitlementGrantTiming: GrantTiming;
|
|
54
|
+
DefaultEntitlementQuantityMode: QuantityMode;
|
|
55
|
+
DefaultEntitlementValidityMode: ValidityMode;
|
|
56
|
+
}
|
|
57
|
+
export interface ResolvedEntitlementPolicy {
|
|
58
|
+
GrantTiming: GrantTiming;
|
|
59
|
+
QuantityMode: QuantityMode;
|
|
60
|
+
ValidityMode: ValidityMode;
|
|
61
|
+
/** Which level decided each one, for the support question "why did this happen?". */
|
|
62
|
+
DecidedAt: {
|
|
63
|
+
GrantTiming: PolicyLevel;
|
|
64
|
+
QuantityMode: PolicyLevel;
|
|
65
|
+
ValidityMode: PolicyLevel;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Walk the chain for all three settings at once.
|
|
70
|
+
*
|
|
71
|
+
* ONE walk rather than three, because they resolve identically and a caller that walked separately
|
|
72
|
+
* would do the same lookups three times and could be given three different category chains.
|
|
73
|
+
*
|
|
74
|
+
* `entitlement` is consulted for VALIDITY ONLY — see the module header. Timing and quantity are
|
|
75
|
+
* properties of the purchase, not of the individual thing granted: it would make no sense for one
|
|
76
|
+
* entitlement on a line to appear at confirm and another to wait for payment.
|
|
77
|
+
*/
|
|
78
|
+
export declare function ResolveEntitlementPolicy(product: EntitlementPolicySource,
|
|
79
|
+
/** NEAREST FIRST: the product's own category, then its parent, up to the root. */
|
|
80
|
+
categoryChain: PolicyCategoryLevel[], type: PolicyTypeDefaults, entitlement?: {
|
|
81
|
+
ValidityMode: ValidityMode | null;
|
|
82
|
+
} | null): ResolvedEntitlementPolicy;
|
|
83
|
+
/**
|
|
84
|
+
* How much of the entitlement this line grants.
|
|
85
|
+
*
|
|
86
|
+
* `PerUnit` multiplies, so three 5-seat packs give fifteen seats — which is what somebody buying
|
|
87
|
+
* three packs expects. `Flat` ignores the line quantity entirely, for entitlements that are not
|
|
88
|
+
* countable: "access to the member portal" does not become three portals.
|
|
89
|
+
*
|
|
90
|
+
* ROUNDED UP, and only ever up. A prorated subscription line carries a fractional quantity (0.5833
|
|
91
|
+
* for a short first period), and 0.5833 × 5 seats is 2.9165. Rounding down hands the customer two
|
|
92
|
+
* seats for a five-seat product and generates a support ticket; rounding up hands them three and
|
|
93
|
+
* generates nothing. Under-granting is the expensive direction, exactly as under-collecting is with
|
|
94
|
+
* tax, and for the same reason: the customer notices.
|
|
95
|
+
*
|
|
96
|
+
* A null template quantity means the entitlement is not a countable thing (a Feature or AccessLevel
|
|
97
|
+
* rather than a ResourceQuantity), and stays null rather than becoming zero — zero would read as
|
|
98
|
+
* "granted none of it".
|
|
99
|
+
*/
|
|
100
|
+
export declare function ResolveGrantQuantity(templateQuantity: number | null, lineQuantity: number, mode: QuantityMode): number | null;
|
|
101
|
+
/** Everything a validity window might need to know, so the pure function needs no lookups. */
|
|
102
|
+
export interface ValidityContext {
|
|
103
|
+
/** When the grant takes effect — normally the order date. */
|
|
104
|
+
GrantedOn: Date;
|
|
105
|
+
/** FixedDuration only. */
|
|
106
|
+
DurationDays?: number | null;
|
|
107
|
+
/** EventWindow only: the event's own dates, and how far either side access opens. */
|
|
108
|
+
EventStartsAt?: Date | null;
|
|
109
|
+
EventEndsAt?: Date | null;
|
|
110
|
+
AccessLeadHours?: number | null;
|
|
111
|
+
AccessLagHours?: number | null;
|
|
112
|
+
/** SubscriptionTerm only. */
|
|
113
|
+
TermStartDate?: Date | null;
|
|
114
|
+
TermEndDate?: Date | null;
|
|
115
|
+
}
|
|
116
|
+
export interface ResolvedValidity {
|
|
117
|
+
ValidFrom: Date;
|
|
118
|
+
/** NULL means perpetual. A grant with no end is a real thing, not a missing value. */
|
|
119
|
+
ValidTo: Date | null;
|
|
120
|
+
ModeApplied: ValidityMode;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Turn a validity mode plus its context into an actual window.
|
|
124
|
+
*
|
|
125
|
+
* FALLS BACK RATHER THAN THROWING when a mode's own inputs are missing, and records what it actually
|
|
126
|
+
* applied. A ticket whose product has no event dates should not fail the customer's order — but the
|
|
127
|
+
* grant must not silently claim to be an event window either, so `ModeApplied` says `Perpetual` and
|
|
128
|
+
* an auditor can see the mode was requested and could not be honoured.
|
|
129
|
+
*
|
|
130
|
+
* The one thing it will not do is produce a window that ends before it starts. An event whose end
|
|
131
|
+
* date precedes its start, or a lag that somehow lands behind the lead, yields a window ending at its
|
|
132
|
+
* own start — an instantaneous grant, which reads as "nothing was granted" and is at least honest,
|
|
133
|
+
* rather than a negative window the database CHECK would reject at insert time with an error naming
|
|
134
|
+
* neither the product nor the event.
|
|
135
|
+
*/
|
|
136
|
+
export declare function ResolveValidityWindow(mode: ValidityMode, ctx: ValidityContext): ResolvedValidity;
|
|
137
|
+
/**
|
|
138
|
+
* Should the grant be ACTIVE yet, given when access is supposed to begin?
|
|
139
|
+
*
|
|
140
|
+
* The grant row is written at confirm either way — downstream apps poll grants (D27), and a grant
|
|
141
|
+
* that does not exist until payment clears cannot be seen coming. What timing changes is the STATUS:
|
|
142
|
+
*
|
|
143
|
+
* OnConfirm Active immediately. A confirmed order is a claim on the seller.
|
|
144
|
+
* OnPaidInFull Suspended until the order's balance reaches zero. Access follows cash.
|
|
145
|
+
* OnActivation Suspended until something explicitly activates it. Note that nothing does yet —
|
|
146
|
+
* this exists because it was asked for, and a deployment choosing it is choosing to
|
|
147
|
+
* grant nothing until it builds the caller.
|
|
148
|
+
*
|
|
149
|
+
* `Suspended` rather than a missing row, and rather than `Revoked`: revoked means somebody took it
|
|
150
|
+
* away, which is a different fact that an access dispute turns on.
|
|
151
|
+
*/
|
|
152
|
+
export declare function InitialGrantStatus(timing: GrantTiming, order: {
|
|
153
|
+
Balance: number | null;
|
|
154
|
+
TotalGross: number | null;
|
|
155
|
+
}): 'Active' | 'Suspended';
|
|
156
|
+
/**
|
|
157
|
+
* How much of a grant survives a partial return.
|
|
158
|
+
*
|
|
159
|
+
* A customer who bought five seats and sent two back keeps three. Returning everything revokes the
|
|
160
|
+
* grant outright rather than leaving a zero-quantity row, because zero is indistinguishable from a
|
|
161
|
+
* Feature grant that never had a quantity.
|
|
162
|
+
*/
|
|
163
|
+
export declare function ReduceGrantForReturn(grantQuantity: number | null, originalLineQuantity: number, returnedQuantity: number): {
|
|
164
|
+
Quantity: number | null;
|
|
165
|
+
Revoke: boolean;
|
|
166
|
+
};
|
|
167
|
+
/** Why a check granted or refused. Collapsing these to a boolean loses the support conversation. */
|
|
168
|
+
export type EntitlementDecision = 'Granted' | 'NoGrant' | 'NotYetValid' | 'Expired' | 'Revoked' | 'Suspended' | 'SubscriptionInactive';
|
|
169
|
+
/** The facts a grant row carries that the evaluator needs — no database. */
|
|
170
|
+
export interface GrantAccessFacts {
|
|
171
|
+
Status: string;
|
|
172
|
+
ValidFrom: Date | null;
|
|
173
|
+
ValidTo: Date | null;
|
|
174
|
+
/** True when `EntitlementGrant.SubscriptionID` is set. Missing subscription row → fail closed. */
|
|
175
|
+
LinkedToSubscription?: boolean;
|
|
176
|
+
/** True when `EntitlementGrant.SubscriptionTermID` is set. Missing term row → fail closed. */
|
|
177
|
+
LinkedToTerm?: boolean;
|
|
178
|
+
}
|
|
179
|
+
/** Subscription facts that can cut access short or extend it through grace. */
|
|
180
|
+
export interface SubscriptionAccessFacts {
|
|
181
|
+
Status: string;
|
|
182
|
+
/**
|
|
183
|
+
* When the subscription is `Canceled`, this is access-through (`EndDate` stamped from
|
|
184
|
+
* `CancellationDecision.AccessThroughDate`). Ignored while the sub is Active/Trialing.
|
|
185
|
+
*/
|
|
186
|
+
EndDate: Date | null;
|
|
187
|
+
}
|
|
188
|
+
export interface TermAccessFacts {
|
|
189
|
+
Status: string;
|
|
190
|
+
StartDate: Date;
|
|
191
|
+
EndDate: Date;
|
|
192
|
+
}
|
|
193
|
+
export interface GrantAccessEvaluation {
|
|
194
|
+
HasAccess: boolean;
|
|
195
|
+
Decision: EntitlementDecision;
|
|
196
|
+
ValidFrom: Date | null;
|
|
197
|
+
ValidTo: Date | null;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Is this grant in force at `asOf`?
|
|
201
|
+
*
|
|
202
|
+
* ONE function, because a second “is this in force” will drift from the first — that failure
|
|
203
|
+
* has already bitten this codebase twice. Bounds are inclusive: access holds at the exact
|
|
204
|
+
* `ValidFrom` / `ValidTo` / cancel `EndDate` instant.
|
|
205
|
+
*
|
|
206
|
+
* Cancelled subscriptions are the interesting case. The grant's `ValidTo` is the original term
|
|
207
|
+
* end, which is a LIE after an immediate cancel: access-through is `subscription.EndDate`
|
|
208
|
+
* (grace included). Grace can also EXTEND past `ValidTo`. Either way, `EndDate` is the bound
|
|
209
|
+
* once the sub is `Canceled`. Paused/Migrated refuse immediately — they have no grace story.
|
|
210
|
+
*/
|
|
211
|
+
export declare function EvaluateGrantAccess(grant: GrantAccessFacts, asOf: Date, subscription?: SubscriptionAccessFacts | null, term?: TermAccessFacts | null): GrantAccessEvaluation;
|
|
212
|
+
export interface RankableAccess {
|
|
213
|
+
HasAccess: boolean;
|
|
214
|
+
Decision: EntitlementDecision;
|
|
215
|
+
ValidTo: Date | null;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* One answer from many grants for the same Code. A Granted perpetual beats a Granted with an
|
|
219
|
+
* end; among denials the most useful reason wins, not the most recent row.
|
|
220
|
+
*/
|
|
221
|
+
export declare function PickWinningAccess<T extends RankableAccess>(results: T[]): T | null;
|
|
222
|
+
/** Default CacheUntil cap for a check answer. Short so a revoke is felt quickly. */
|
|
223
|
+
export declare const ENTITLEMENT_CHECK_TTL_MS = 60000;
|
|
224
|
+
/**
|
|
225
|
+
* When the caller may reuse this answer. Never past `ValidTo` on a grant that is in force —
|
|
226
|
+
* caching a Granted past its own end is how paid content stays open after the window closed.
|
|
227
|
+
*/
|
|
228
|
+
export declare function CacheUntilFor(evaluatedAt: Date, validTo: Date | null | undefined, hasAccess: boolean): Date;
|
|
229
|
+
/**
|
|
230
|
+
* After `Orders.CancelSubscription`, stored grant Status is a lie unless we revoke when
|
|
231
|
+
* access has already ended. Grace (`AccessThroughDate` in the future) leaves the rows
|
|
232
|
+
* standing — the evaluator honours `subscription.EndDate`.
|
|
233
|
+
*/
|
|
234
|
+
export declare function ShouldRevokeGrantsOnCancel(accessThroughDate: Date, now: Date): boolean;
|
|
235
|
+
//# sourceMappingURL=EntitlementBehavior.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EntitlementBehavior.d.ts","sourceRoot":"","sources":["../src/EntitlementBehavior.ts"],"names":[],"mappings":"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"}
|