@metamask/subscription-controller 6.2.2 → 8.0.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/CHANGELOG.md +54 -1
- package/dist/SubscriptionController-method-action-types.cjs.map +1 -1
- package/dist/SubscriptionController-method-action-types.d.cts +55 -18
- package/dist/SubscriptionController-method-action-types.d.cts.map +1 -1
- package/dist/SubscriptionController-method-action-types.d.mts +55 -18
- package/dist/SubscriptionController-method-action-types.d.mts.map +1 -1
- package/dist/SubscriptionController-method-action-types.mjs.map +1 -1
- package/dist/SubscriptionController.cjs +180 -68
- package/dist/SubscriptionController.cjs.map +1 -1
- package/dist/SubscriptionController.d.cts +58 -26
- package/dist/SubscriptionController.d.cts.map +1 -1
- package/dist/SubscriptionController.d.mts +58 -26
- package/dist/SubscriptionController.d.mts.map +1 -1
- package/dist/SubscriptionController.mjs +181 -69
- package/dist/SubscriptionController.mjs.map +1 -1
- package/dist/SubscriptionService-method-action-types.cjs +7 -0
- package/dist/SubscriptionService-method-action-types.cjs.map +1 -0
- package/dist/SubscriptionService-method-action-types.d.cts +155 -0
- package/dist/SubscriptionService-method-action-types.d.cts.map +1 -0
- package/dist/SubscriptionService-method-action-types.d.mts +155 -0
- package/dist/SubscriptionService-method-action-types.d.mts.map +1 -0
- package/dist/SubscriptionService-method-action-types.mjs +6 -0
- package/dist/SubscriptionService-method-action-types.mjs.map +1 -0
- package/dist/SubscriptionService-structs.cjs +158 -0
- package/dist/SubscriptionService-structs.cjs.map +1 -0
- package/dist/SubscriptionService-structs.d.cts +721 -0
- package/dist/SubscriptionService-structs.d.cts.map +1 -0
- package/dist/SubscriptionService-structs.d.mts +721 -0
- package/dist/SubscriptionService-structs.d.mts.map +1 -0
- package/dist/SubscriptionService-structs.mjs +155 -0
- package/dist/SubscriptionService-structs.mjs.map +1 -0
- package/dist/SubscriptionService.cjs +279 -87
- package/dist/SubscriptionService.cjs.map +1 -1
- package/dist/SubscriptionService.d.cts +94 -10
- package/dist/SubscriptionService.d.cts.map +1 -1
- package/dist/SubscriptionService.d.mts +94 -10
- package/dist/SubscriptionService.d.mts.map +1 -1
- package/dist/SubscriptionService.mjs +279 -87
- package/dist/SubscriptionService.mjs.map +1 -1
- package/dist/constants.cjs +2 -0
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +2 -0
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.mts +2 -0
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +2 -0
- package/dist/constants.mjs.map +1 -1
- package/dist/index.cjs +4 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -6
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +7 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/types.cjs +27 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +171 -10
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +171 -10
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +26 -0
- package/dist/types.mjs.map +1 -1
- package/package.json +5 -2
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
-
};
|
|
8
2
|
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
3
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
4
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
5
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
6
|
};
|
|
13
|
-
var _SubscriptionController_instances,
|
|
7
|
+
var _SubscriptionController_instances, _SubscriptionController_getSubscriptionPriceAmount, _SubscriptionController_getSubscriptionBalanceAmount, _SubscriptionController_getProductPriceByProductAndPlan, _SubscriptionController_assertValidSubscriptionStateForCryptoApproval, _SubscriptionController_assertIsUserNotSubscribed, _SubscriptionController_assertIsUserSubscribed, _SubscriptionController_assertIsPaymentMethodCrypto, _SubscriptionController_getIsEligibleForTrialedSponsorship, _SubscriptionController_getIsTrialRequested, _SubscriptionController_findCryptoPaymentMethod, _SubscriptionController_resolveCryptoPaymentMethodDefaults, _SubscriptionController_getChainSupportsSponsorship, _SubscriptionController_areTrialedProductsEqual, _SubscriptionController_areSubscriptionsEqual, _SubscriptionController_isSubscriptionEqual, _SubscriptionController_stringifySubscription;
|
|
14
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
9
|
exports.SubscriptionController = exports.getDefaultSubscriptionControllerState = void 0;
|
|
16
10
|
const polling_controller_1 = require("@metamask/polling-controller");
|
|
@@ -88,10 +82,10 @@ const MESSENGER_EXPOSED_METHODS = [
|
|
|
88
82
|
'getSubscriptionsEligibilities',
|
|
89
83
|
'cancelSubscription',
|
|
90
84
|
'unCancelSubscription',
|
|
91
|
-
'
|
|
85
|
+
'startSubscriptionWithCard',
|
|
92
86
|
'startSubscriptionWithCrypto',
|
|
93
87
|
'stopAllPolling',
|
|
94
|
-
'
|
|
88
|
+
'submitSubscriptionCryptoApproval',
|
|
95
89
|
'getCryptoApproveTransactionParams',
|
|
96
90
|
'updatePaymentMethod',
|
|
97
91
|
'getBillingPortalUrl',
|
|
@@ -113,10 +107,10 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
113
107
|
* @param options - The options for the SubscriptionController.
|
|
114
108
|
* @param options.messenger - A restricted messenger.
|
|
115
109
|
* @param options.state - Initial state to set on this controller.
|
|
116
|
-
* @param options.subscriptionService - The subscription service for communicating with subscription server.
|
|
117
110
|
* @param options.pollingInterval - The polling interval to use for the subscription controller.
|
|
118
111
|
*/
|
|
119
|
-
constructor(
|
|
112
|
+
constructor(options) {
|
|
113
|
+
const { messenger, state, pollingInterval = constants_js_1.DEFAULT_POLLING_INTERVAL, } = options;
|
|
120
114
|
super({
|
|
121
115
|
name: constants_js_1.controllerName,
|
|
122
116
|
metadata: subscriptionControllerMetadata,
|
|
@@ -127,9 +121,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
127
121
|
messenger,
|
|
128
122
|
});
|
|
129
123
|
_SubscriptionController_instances.add(this);
|
|
130
|
-
_SubscriptionController_subscriptionService.set(this, void 0);
|
|
131
124
|
this.setIntervalLength(pollingInterval);
|
|
132
|
-
__classPrivateFieldSet(this, _SubscriptionController_subscriptionService, subscriptionService, "f");
|
|
133
125
|
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
134
126
|
}
|
|
135
127
|
/**
|
|
@@ -138,7 +130,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
138
130
|
* @returns The pricing information.
|
|
139
131
|
*/
|
|
140
132
|
async getPricing() {
|
|
141
|
-
const pricing = await
|
|
133
|
+
const pricing = await this.messenger.call('SubscriptionService:getPricing');
|
|
142
134
|
this.update((state) => {
|
|
143
135
|
state.pricing = pricing;
|
|
144
136
|
});
|
|
@@ -150,7 +142,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
150
142
|
const currentCustomerId = this.state.customerId;
|
|
151
143
|
const currentLastSubscription = this.state.lastSubscription;
|
|
152
144
|
const currentRewardAccountId = this.state.rewardAccountId;
|
|
153
|
-
const { customerId: newCustomerId, subscriptions: newSubscriptions, trialedProducts: newTrialedProducts, lastSubscription: newLastSubscription, rewardAccountId: newRewardAccountId, } = await
|
|
145
|
+
const { customerId: newCustomerId, subscriptions: newSubscriptions, trialedProducts: newTrialedProducts, lastSubscription: newLastSubscription, rewardAccountId: newRewardAccountId, } = await this.messenger.call('SubscriptionService:getSubscriptions');
|
|
154
146
|
// check if the new subscriptions are different from the current subscriptions
|
|
155
147
|
const areSubscriptionsEqual = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_areSubscriptionsEqual).call(this, currentSubscriptions, newSubscriptions);
|
|
156
148
|
// check if the new trialed products are different from the current trialed products
|
|
@@ -194,11 +186,11 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
194
186
|
* @returns The subscriptions eligibilities.
|
|
195
187
|
*/
|
|
196
188
|
async getSubscriptionsEligibilities(request) {
|
|
197
|
-
return await
|
|
189
|
+
return await this.messenger.call('SubscriptionService:getSubscriptionsEligibilities', request);
|
|
198
190
|
}
|
|
199
191
|
async cancelSubscription(request) {
|
|
200
192
|
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertIsUserSubscribed).call(this, { subscriptionId: request.subscriptionId });
|
|
201
|
-
const cancelledSubscription = await
|
|
193
|
+
const cancelledSubscription = await this.messenger.call('SubscriptionService:cancelSubscription', request);
|
|
202
194
|
this.update((state) => {
|
|
203
195
|
state.subscriptions = state.subscriptions.map((subscription) => subscription.id === request.subscriptionId
|
|
204
196
|
? { ...subscription, ...cancelledSubscription }
|
|
@@ -208,7 +200,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
208
200
|
}
|
|
209
201
|
async unCancelSubscription(request) {
|
|
210
202
|
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertIsUserSubscribed).call(this, { subscriptionId: request.subscriptionId });
|
|
211
|
-
const uncancelledSubscription = await
|
|
203
|
+
const uncancelledSubscription = await this.messenger.call('SubscriptionService:unCancelSubscription', {
|
|
212
204
|
subscriptionId: request.subscriptionId,
|
|
213
205
|
});
|
|
214
206
|
this.update((state) => {
|
|
@@ -218,51 +210,107 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
218
210
|
});
|
|
219
211
|
this.triggerAccessTokenRefresh();
|
|
220
212
|
}
|
|
221
|
-
|
|
213
|
+
/**
|
|
214
|
+
* Starts a card-paid subscription checkout session for the requested products
|
|
215
|
+
* (e.g. Shield or Money Account Plus).
|
|
216
|
+
*
|
|
217
|
+
* `isTrialRequested` on the request is ignored and overwritten from pricing
|
|
218
|
+
* (`trialPeriodDays > 0`) and `trialedProducts`.
|
|
219
|
+
*
|
|
220
|
+
* @param request - The start subscription request.
|
|
221
|
+
* @returns The checkout session response.
|
|
222
|
+
*/
|
|
223
|
+
async startSubscriptionWithCard(request) {
|
|
224
|
+
// get the latest subscriptions state before computing trial eligibility
|
|
225
|
+
await this.getSubscriptions();
|
|
222
226
|
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertIsUserNotSubscribed).call(this, { products: request.products });
|
|
223
|
-
const response = await
|
|
227
|
+
const response = await this.messenger.call('SubscriptionService:startSubscriptionWithCard', {
|
|
228
|
+
...request,
|
|
229
|
+
isTrialRequested: __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_getIsTrialRequested).call(this, request.products, request.recurringInterval),
|
|
230
|
+
});
|
|
224
231
|
// note: no need to trigger access token refresh after startSubscriptionWithCard request because this only return stripe checkout session url, subscription not created yet
|
|
225
232
|
return response;
|
|
226
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Starts a crypto-paid subscription for the requested products
|
|
236
|
+
* (e.g. Shield or Money Account Plus). Unlike card checkout, this
|
|
237
|
+
* creates the subscription immediately, so local state is refreshed
|
|
238
|
+
* afterwards.
|
|
239
|
+
*
|
|
240
|
+
* `isTrialRequested` on the request is ignored and overwritten from pricing
|
|
241
|
+
* (`trialPeriodDays > 0`) and `trialedProducts`.
|
|
242
|
+
*
|
|
243
|
+
* @param request - The start crypto subscription request.
|
|
244
|
+
* @returns The start crypto subscription response.
|
|
245
|
+
* @throws If `products` is empty.
|
|
246
|
+
*/
|
|
227
247
|
async startSubscriptionWithCrypto(request) {
|
|
248
|
+
if (request.products.length === 0) {
|
|
249
|
+
throw new Error(constants_js_1.SubscriptionControllerErrorMessage.SubscriptionProductsEmpty);
|
|
250
|
+
}
|
|
251
|
+
// get the latest subscriptions state before computing trial eligibility
|
|
252
|
+
await this.getSubscriptions();
|
|
228
253
|
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertIsUserNotSubscribed).call(this, { products: request.products });
|
|
229
|
-
const response = await
|
|
254
|
+
const response = await this.messenger.call('SubscriptionService:startSubscriptionWithCrypto', {
|
|
255
|
+
...request,
|
|
256
|
+
isTrialRequested: __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_getIsTrialRequested).call(this, request.products, request.recurringInterval),
|
|
257
|
+
});
|
|
258
|
+
// Crypto start creates the subscription immediately (unlike card checkout).
|
|
259
|
+
await this.getSubscriptions();
|
|
230
260
|
return response;
|
|
231
261
|
}
|
|
232
262
|
/**
|
|
233
|
-
*
|
|
263
|
+
* Submits a Shield ERC-20 crypto approval transaction to start or update a
|
|
264
|
+
* crypto subscription.
|
|
234
265
|
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
266
|
+
* This handler is Shield / `TransactionType.shieldSubscriptionApprove` only.
|
|
267
|
+
* Delegation-based products (e.g. Money Account) must call
|
|
268
|
+
* `startSubscriptionWithCrypto` instead.
|
|
269
|
+
*
|
|
270
|
+
* @param request - The crypto approval request.
|
|
271
|
+
* @param request.productType - The subscription product. Typed as
|
|
272
|
+
* `typeof PRODUCT_TYPES.SHIELD` only at the moment (future might support more
|
|
273
|
+
* product).
|
|
274
|
+
* @param request.txMeta - The transaction metadata. Must have type
|
|
275
|
+
* `TransactionType.shieldSubscriptionApprove`.
|
|
276
|
+
* @param request.isSponsored - Whether the transaction is sponsored.
|
|
277
|
+
* @param request.rewardAccountId - The account ID of the reward subscription
|
|
278
|
+
* to link.
|
|
279
|
+
* @throws If `productType` is not Shield or `txMeta.type` is not
|
|
280
|
+
* `shieldSubscriptionApprove`.
|
|
238
281
|
* @returns void
|
|
239
282
|
*/
|
|
240
|
-
async
|
|
241
|
-
|
|
242
|
-
|
|
283
|
+
async submitSubscriptionCryptoApproval(request) {
|
|
284
|
+
const { productType, txMeta, isSponsored, rewardAccountId } = request;
|
|
285
|
+
if (
|
|
286
|
+
// Widen for the runtime guard: JS / unsound callers may still pass a
|
|
287
|
+
// non-Shield product.
|
|
288
|
+
productType !== types_js_1.PRODUCT_TYPES.SHIELD ||
|
|
289
|
+
txMeta.type !== transaction_controller_1.TransactionType.shieldSubscriptionApprove) {
|
|
290
|
+
throw new Error(constants_js_1.SubscriptionControllerErrorMessage.CryptoApprovalRequiresShieldApprove);
|
|
243
291
|
}
|
|
244
292
|
const { chainId, rawTx } = txMeta;
|
|
245
293
|
if (!chainId || !rawTx) {
|
|
246
294
|
throw new Error('Chain ID or raw transaction not found');
|
|
247
295
|
}
|
|
248
|
-
const { pricing,
|
|
296
|
+
const { pricing, lastSelectedPaymentMethod } = this.state;
|
|
249
297
|
if (!pricing) {
|
|
250
298
|
throw new Error('Subscription pricing not found');
|
|
251
299
|
}
|
|
252
300
|
if (!lastSelectedPaymentMethod) {
|
|
253
301
|
throw new Error('Last selected payment method not found');
|
|
254
302
|
}
|
|
255
|
-
const
|
|
256
|
-
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertIsPaymentMethodCrypto).call(this,
|
|
257
|
-
const productPrice = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_getProductPriceByProductAndPlan).call(this,
|
|
258
|
-
|
|
259
|
-
// get the latest subscriptions state to check if the user has an active shield subscription
|
|
303
|
+
const lastSelectedPaymentMethodForProduct = lastSelectedPaymentMethod[productType];
|
|
304
|
+
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertIsPaymentMethodCrypto).call(this, lastSelectedPaymentMethodForProduct);
|
|
305
|
+
const productPrice = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_getProductPriceByProductAndPlan).call(this, productType, lastSelectedPaymentMethodForProduct.plan);
|
|
306
|
+
// get the latest subscriptions state before computing trial eligibility
|
|
260
307
|
await this.getSubscriptions();
|
|
261
|
-
const
|
|
308
|
+
const isTrialRequested = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_getIsTrialRequested).call(this, [productType], lastSelectedPaymentMethodForProduct.plan);
|
|
309
|
+
const currentSubscription = this.getSubscriptionByProduct(productType);
|
|
262
310
|
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertValidSubscriptionStateForCryptoApproval).call(this, {
|
|
263
|
-
productType
|
|
311
|
+
productType,
|
|
264
312
|
});
|
|
265
|
-
// if
|
|
313
|
+
// if subscription exists, this transaction is for changing payment method
|
|
266
314
|
const isChangePaymentMethod = Boolean(currentSubscription);
|
|
267
315
|
if (isChangePaymentMethod) {
|
|
268
316
|
await this.updatePaymentMethod({
|
|
@@ -270,7 +318,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
270
318
|
subscriptionId: currentSubscription.id,
|
|
271
319
|
chainId,
|
|
272
320
|
payerAddress: txMeta.txParams.from,
|
|
273
|
-
tokenSymbol:
|
|
321
|
+
tokenSymbol: lastSelectedPaymentMethodForProduct.paymentTokenSymbol,
|
|
274
322
|
rawTransaction: rawTx,
|
|
275
323
|
recurringInterval: productPrice.interval,
|
|
276
324
|
billingCycles: productPrice.minBillingCycles,
|
|
@@ -278,16 +326,17 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
278
326
|
}
|
|
279
327
|
else {
|
|
280
328
|
const params = {
|
|
281
|
-
products: [
|
|
282
|
-
isTrialRequested
|
|
329
|
+
products: [productType],
|
|
330
|
+
isTrialRequested,
|
|
283
331
|
recurringInterval: productPrice.interval,
|
|
284
332
|
billingCycles: productPrice.minBillingCycles,
|
|
285
333
|
chainId,
|
|
286
334
|
payerAddress: txMeta.txParams.from,
|
|
287
|
-
tokenSymbol:
|
|
335
|
+
tokenSymbol: lastSelectedPaymentMethodForProduct.paymentTokenSymbol,
|
|
288
336
|
rawTransaction: rawTx,
|
|
337
|
+
cryptoAuthMethod: types_js_1.CRYPTO_AUTH_METHODS.ERC20_APPROVAL,
|
|
289
338
|
isSponsored,
|
|
290
|
-
useTestClock:
|
|
339
|
+
useTestClock: lastSelectedPaymentMethodForProduct.useTestClock,
|
|
291
340
|
rewardAccountId,
|
|
292
341
|
};
|
|
293
342
|
await this.startSubscriptionWithCrypto(params);
|
|
@@ -318,7 +367,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
318
367
|
if (!price) {
|
|
319
368
|
throw new Error('Price not found');
|
|
320
369
|
}
|
|
321
|
-
const chainsPaymentInfo =
|
|
370
|
+
const chainsPaymentInfo = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_findCryptoPaymentMethod).call(this, request.productType, types_js_1.CRYPTO_AUTH_METHODS.ERC20_APPROVAL);
|
|
322
371
|
if (!chainsPaymentInfo) {
|
|
323
372
|
throw new Error('Chains payment info not found');
|
|
324
373
|
}
|
|
@@ -342,11 +391,11 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
342
391
|
async updatePaymentMethod(opts) {
|
|
343
392
|
if (opts.paymentType === types_js_1.PAYMENT_TYPES.byCard) {
|
|
344
393
|
const { paymentType, ...cardRequest } = opts;
|
|
345
|
-
return await
|
|
394
|
+
return await this.messenger.call('SubscriptionService:updatePaymentMethodCard', cardRequest);
|
|
346
395
|
}
|
|
347
396
|
else if (opts.paymentType === types_js_1.PAYMENT_TYPES.byCrypto) {
|
|
348
397
|
const { paymentType, ...cryptoRequest } = opts;
|
|
349
|
-
await
|
|
398
|
+
await this.messenger.call('SubscriptionService:updatePaymentMethodCrypto', cryptoRequest);
|
|
350
399
|
return await this.getSubscriptions();
|
|
351
400
|
}
|
|
352
401
|
throw new Error('Invalid payment type');
|
|
@@ -357,19 +406,20 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
357
406
|
* @returns The billing portal URL
|
|
358
407
|
*/
|
|
359
408
|
async getBillingPortalUrl() {
|
|
360
|
-
return await
|
|
409
|
+
return await this.messenger.call('SubscriptionService:getBillingPortalUrl');
|
|
361
410
|
}
|
|
362
411
|
/**
|
|
363
412
|
* Cache the last selected payment method for a specific product.
|
|
364
413
|
*
|
|
365
|
-
* @param
|
|
366
|
-
* @param
|
|
367
|
-
* @param paymentMethod
|
|
368
|
-
* @param paymentMethod.
|
|
369
|
-
* @param paymentMethod.
|
|
370
|
-
* @param paymentMethod.
|
|
414
|
+
* @param request - The request object.
|
|
415
|
+
* @param request.product - The product to cache the payment method for.
|
|
416
|
+
* @param request.paymentMethod - The payment method to cache.
|
|
417
|
+
* @param request.paymentMethod.type - The type of the payment method.
|
|
418
|
+
* @param request.paymentMethod.paymentTokenAddress - The payment token address.
|
|
419
|
+
* @param request.paymentMethod.plan - The plan of the payment method.
|
|
371
420
|
*/
|
|
372
|
-
cacheLastSelectedPaymentMethod(
|
|
421
|
+
cacheLastSelectedPaymentMethod(request) {
|
|
422
|
+
const { product, paymentMethod } = request;
|
|
373
423
|
if (paymentMethod.type === types_js_1.PAYMENT_TYPES.byCrypto &&
|
|
374
424
|
(!paymentMethod.paymentTokenAddress || !paymentMethod.paymentTokenSymbol)) {
|
|
375
425
|
throw new Error(constants_js_1.SubscriptionControllerErrorMessage.PaymentTokenAddressAndSymbolRequiredForCrypto);
|
|
@@ -408,7 +458,8 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
408
458
|
* recurringInterval: RecurringInterval.Month,
|
|
409
459
|
* billingCycles: 1,
|
|
410
460
|
* }
|
|
411
|
-
* @returns resolves to true if the sponsorship is supported and intents were submitted successfully, false
|
|
461
|
+
* @returns resolves to true if the sponsorship is supported and intents were submitted successfully, false if the chain does not support sponsorship or the user has already trialed
|
|
462
|
+
* @throws If the crypto payment method or chain is missing from pricing
|
|
412
463
|
*/
|
|
413
464
|
async submitSponsorshipIntents(request) {
|
|
414
465
|
if (request.products.length === 0) {
|
|
@@ -417,7 +468,9 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
417
468
|
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertIsUserNotSubscribed).call(this, { products: request.products });
|
|
418
469
|
const selectedPaymentMethod = this.state.lastSelectedPaymentMethod?.[request.products[0]];
|
|
419
470
|
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertIsPaymentMethodCrypto).call(this, selectedPaymentMethod);
|
|
420
|
-
const
|
|
471
|
+
const cryptoAuthMethod = selectedPaymentMethod.cryptoAuthMethod ??
|
|
472
|
+
types_js_1.CRYPTO_AUTH_METHODS.ERC20_APPROVAL;
|
|
473
|
+
const isEligibleForTrialedSponsorship = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_getIsEligibleForTrialedSponsorship).call(this, request.chainId, request.products, cryptoAuthMethod);
|
|
421
474
|
if (!isEligibleForTrialedSponsorship) {
|
|
422
475
|
return false;
|
|
423
476
|
}
|
|
@@ -426,7 +479,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
426
479
|
// we only support one product at a time for now
|
|
427
480
|
request.products[0], plan);
|
|
428
481
|
const billingCycles = productPrice.minBillingCycles;
|
|
429
|
-
await
|
|
482
|
+
await this.messenger.call('SubscriptionService:submitSponsorshipIntents', {
|
|
430
483
|
...request,
|
|
431
484
|
paymentTokenSymbol,
|
|
432
485
|
billingCycles,
|
|
@@ -441,7 +494,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
441
494
|
* @example { event: SubscriptionUserEvent.ShieldEntryModalViewed, cohort: 'post_tx' }
|
|
442
495
|
*/
|
|
443
496
|
async submitUserEvent(request) {
|
|
444
|
-
await
|
|
497
|
+
await this.messenger.call('SubscriptionService:submitUserEvent', request);
|
|
445
498
|
}
|
|
446
499
|
/**
|
|
447
500
|
* Assign user to a cohort.
|
|
@@ -450,7 +503,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
450
503
|
* @example { cohort: 'post_tx' }
|
|
451
504
|
*/
|
|
452
505
|
async assignUserToCohort(request) {
|
|
453
|
-
await
|
|
506
|
+
await this.messenger.call('SubscriptionService:assignUserToCohort', request);
|
|
454
507
|
}
|
|
455
508
|
/**
|
|
456
509
|
* Link rewards to a subscription.
|
|
@@ -465,7 +518,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
465
518
|
// assert that the user is subscribed to the subscription
|
|
466
519
|
__classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_assertIsUserSubscribed).call(this, { subscriptionId: request.subscriptionId });
|
|
467
520
|
// link rewards to the subscription
|
|
468
|
-
const response = await
|
|
521
|
+
const response = await this.messenger.call('SubscriptionService:linkRewards', {
|
|
469
522
|
rewardAccountId: request.rewardAccountId,
|
|
470
523
|
});
|
|
471
524
|
if (!response.success) {
|
|
@@ -483,7 +536,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
483
536
|
* @returns The token approve amount
|
|
484
537
|
*/
|
|
485
538
|
getTokenApproveAmount(price, tokenPaymentInfo) {
|
|
486
|
-
const conversionRate = tokenPaymentInfo.conversionRate[price.currency];
|
|
539
|
+
const conversionRate = tokenPaymentInfo.conversionRate?.[price.currency];
|
|
487
540
|
if (!conversionRate) {
|
|
488
541
|
throw new Error('Conversion rate not found');
|
|
489
542
|
}
|
|
@@ -503,7 +556,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
503
556
|
* @returns The token balance amount
|
|
504
557
|
*/
|
|
505
558
|
getTokenMinimumBalanceAmount(price, tokenPaymentInfo) {
|
|
506
|
-
const conversionRate = tokenPaymentInfo.conversionRate[price.currency];
|
|
559
|
+
const conversionRate = tokenPaymentInfo.conversionRate?.[price.currency];
|
|
507
560
|
if (!conversionRate) {
|
|
508
561
|
throw new Error('Conversion rate not found');
|
|
509
562
|
}
|
|
@@ -534,7 +587,7 @@ class SubscriptionController extends (0, polling_controller_1.StaticIntervalPoll
|
|
|
534
587
|
}
|
|
535
588
|
}
|
|
536
589
|
exports.SubscriptionController = SubscriptionController;
|
|
537
|
-
|
|
590
|
+
_SubscriptionController_instances = new WeakSet(), _SubscriptionController_getSubscriptionPriceAmount = function _SubscriptionController_getSubscriptionPriceAmount(price) {
|
|
538
591
|
// no need to use BigInt since max unitDecimals are always 2 for price
|
|
539
592
|
const amount = new bignumber_js_1.BigNumber(price.unitAmount)
|
|
540
593
|
.div(10 ** price.unitDecimals)
|
|
@@ -586,15 +639,74 @@ _SubscriptionController_subscriptionService = new WeakMap(), _SubscriptionContro
|
|
|
586
639
|
!value.paymentTokenSymbol) {
|
|
587
640
|
throw new Error(constants_js_1.SubscriptionControllerErrorMessage.PaymentMethodNotCrypto);
|
|
588
641
|
}
|
|
589
|
-
}, _SubscriptionController_getIsEligibleForTrialedSponsorship = function _SubscriptionController_getIsEligibleForTrialedSponsorship(chainId, products) {
|
|
590
|
-
const isSponsorshipSupported = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_getChainSupportsSponsorship).call(this, chainId);
|
|
642
|
+
}, _SubscriptionController_getIsEligibleForTrialedSponsorship = function _SubscriptionController_getIsEligibleForTrialedSponsorship(chainId, products, cryptoAuthMethod) {
|
|
643
|
+
const isSponsorshipSupported = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_getChainSupportsSponsorship).call(this, chainId, products[0], cryptoAuthMethod);
|
|
591
644
|
// verify if the user has trialed the provided products before
|
|
592
645
|
const hasTrialedBefore = this.state.trialedProducts.some((product) => products.includes(product));
|
|
593
646
|
return isSponsorshipSupported && !hasTrialedBefore;
|
|
594
|
-
},
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
647
|
+
}, _SubscriptionController_getIsTrialRequested = function _SubscriptionController_getIsTrialRequested(products, plan) {
|
|
648
|
+
return products.every((productType) => {
|
|
649
|
+
if (this.state.trialedProducts.includes(productType)) {
|
|
650
|
+
return false;
|
|
651
|
+
}
|
|
652
|
+
const productPrice = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_getProductPriceByProductAndPlan).call(this, productType, plan);
|
|
653
|
+
return productPrice.trialPeriodDays > 0;
|
|
654
|
+
});
|
|
655
|
+
}, _SubscriptionController_findCryptoPaymentMethod = function _SubscriptionController_findCryptoPaymentMethod(productType, cryptoAuthMethod) {
|
|
656
|
+
const matches = [];
|
|
657
|
+
for (const paymentMethod of this.state.pricing?.paymentMethods ?? []) {
|
|
658
|
+
if (paymentMethod.type !== types_js_1.PAYMENT_TYPES.byCrypto) {
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
const resolved = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_resolveCryptoPaymentMethodDefaults).call(this, paymentMethod);
|
|
662
|
+
if (!resolved) {
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
if (resolved.cryptoAuthMethod === cryptoAuthMethod &&
|
|
666
|
+
resolved.products.includes(productType)) {
|
|
667
|
+
matches.push({
|
|
668
|
+
method: paymentMethod,
|
|
669
|
+
explicit: resolved.explicit,
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (matches.length === 0) {
|
|
674
|
+
return undefined;
|
|
675
|
+
}
|
|
676
|
+
const explicitMatches = matches.filter((match) => match.explicit);
|
|
677
|
+
const candidates = explicitMatches.length > 0 ? explicitMatches : matches;
|
|
678
|
+
if (candidates.length > 1) {
|
|
679
|
+
throw new Error('Multiple matching crypto payment methods found');
|
|
680
|
+
}
|
|
681
|
+
return candidates[0].method;
|
|
682
|
+
}, _SubscriptionController_resolveCryptoPaymentMethodDefaults = function _SubscriptionController_resolveCryptoPaymentMethodDefaults(paymentMethod) {
|
|
683
|
+
const productsPresent = paymentMethod.products !== undefined;
|
|
684
|
+
const authPresent = paymentMethod.cryptoAuthMethod !== undefined;
|
|
685
|
+
if (!productsPresent && !authPresent) {
|
|
686
|
+
return {
|
|
687
|
+
products: [types_js_1.PRODUCT_TYPES.SHIELD],
|
|
688
|
+
cryptoAuthMethod: types_js_1.CRYPTO_AUTH_METHODS.ERC20_APPROVAL,
|
|
689
|
+
explicit: false,
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
if (!paymentMethod.products?.length || !paymentMethod.cryptoAuthMethod) {
|
|
693
|
+
return undefined;
|
|
694
|
+
}
|
|
695
|
+
return {
|
|
696
|
+
products: paymentMethod.products,
|
|
697
|
+
cryptoAuthMethod: paymentMethod.cryptoAuthMethod,
|
|
698
|
+
explicit: true,
|
|
699
|
+
};
|
|
700
|
+
}, _SubscriptionController_getChainSupportsSponsorship = function _SubscriptionController_getChainSupportsSponsorship(chainId, productType, cryptoAuthMethod) {
|
|
701
|
+
const cryptoPaymentInfo = __classPrivateFieldGet(this, _SubscriptionController_instances, "m", _SubscriptionController_findCryptoPaymentMethod).call(this, productType, cryptoAuthMethod);
|
|
702
|
+
if (!cryptoPaymentInfo) {
|
|
703
|
+
throw new Error('Chains payment info not found');
|
|
704
|
+
}
|
|
705
|
+
const chainPaymentInfo = cryptoPaymentInfo.chains?.find((chain) => chain.chainId === chainId);
|
|
706
|
+
if (!chainPaymentInfo) {
|
|
707
|
+
throw new Error('Invalid chain id');
|
|
708
|
+
}
|
|
709
|
+
return Boolean(chainPaymentInfo.isSponsorshipSupported);
|
|
598
710
|
}, _SubscriptionController_areTrialedProductsEqual = function _SubscriptionController_areTrialedProductsEqual(oldTrialedProducts, newTrialedProducts) {
|
|
599
711
|
return (oldTrialedProducts.length === newTrialedProducts?.length &&
|
|
600
712
|
oldTrialedProducts.every((product) => newTrialedProducts?.includes(product)));
|