payment-kit 1.25.5 → 1.25.7
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/api/src/libs/wallet-migration.ts +9 -32
- package/api/src/routes/subscriptions.ts +161 -0
- package/blocklet.yml +1 -1
- package/package.json +6 -6
|
@@ -34,11 +34,6 @@ export async function getMigratedFromList(client: OcapClient): Promise<string[]>
|
|
|
34
34
|
cachedMigratedFrom &&
|
|
35
35
|
cachedMigratedFrom.length > 0
|
|
36
36
|
) {
|
|
37
|
-
logger.info('wallet-migration: using cached migratedFrom list', {
|
|
38
|
-
walletAddress: wallet.address,
|
|
39
|
-
chainHost,
|
|
40
|
-
migratedFromCount: cachedMigratedFrom.length,
|
|
41
|
-
});
|
|
42
37
|
return cachedMigratedFrom;
|
|
43
38
|
}
|
|
44
39
|
|
|
@@ -49,13 +44,13 @@ export async function getMigratedFromList(client: OcapClient): Promise<string[]>
|
|
|
49
44
|
cachedWalletAddress = wallet.address;
|
|
50
45
|
cachedChainHost = chainHost;
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
47
|
+
if (cachedMigratedFrom.length > 0) {
|
|
48
|
+
logger.info('wallet-migration: loaded migratedFrom list', {
|
|
49
|
+
walletAddress: wallet.address,
|
|
50
|
+
chainHost,
|
|
51
|
+
migratedFrom: cachedMigratedFrom,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
59
54
|
|
|
60
55
|
return cachedMigratedFrom;
|
|
61
56
|
} catch (err) {
|
|
@@ -108,23 +103,11 @@ export async function getDelegationAddressWithFallback({
|
|
|
108
103
|
// @ts-ignore - OcapClient has host property
|
|
109
104
|
const chainHost = client?.config?.httpEndpoint || 'unknown';
|
|
110
105
|
|
|
111
|
-
logger.info('wallet-migration: getDelegationAddressWithFallback called', {
|
|
112
|
-
delegator,
|
|
113
|
-
storedAddress: storedAddress || null,
|
|
114
|
-
walletAddress: wallet.address,
|
|
115
|
-
chainHost,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
106
|
// 1. Check stored delegation_address first - but verify it has valid state
|
|
119
107
|
if (storedAddress) {
|
|
120
108
|
try {
|
|
121
109
|
const { state: storedState } = await client.getDelegateState({ address: storedAddress });
|
|
122
110
|
if (storedState?.ops?.length > 0) {
|
|
123
|
-
logger.info('wallet-migration: found valid delegation at stored address', {
|
|
124
|
-
storedAddress,
|
|
125
|
-
delegator,
|
|
126
|
-
opsCount: storedState.ops.length,
|
|
127
|
-
});
|
|
128
111
|
return { address: storedAddress, needsBackfill: false, source: 'stored' };
|
|
129
112
|
}
|
|
130
113
|
logger.warn('wallet-migration: stored delegation address has no valid state, falling back', {
|
|
@@ -156,12 +139,6 @@ export async function getDelegationAddressWithFallback({
|
|
|
156
139
|
opsCount: currentState?.ops?.length || 0,
|
|
157
140
|
};
|
|
158
141
|
if (currentState?.ops?.length > 0) {
|
|
159
|
-
logger.info('wallet-migration: found valid delegation at current address', {
|
|
160
|
-
currentAddress,
|
|
161
|
-
delegator,
|
|
162
|
-
walletAddress: wallet.address,
|
|
163
|
-
opsCount: currentState.ops.length,
|
|
164
|
-
});
|
|
165
142
|
return { address: currentAddress, needsBackfill: true, source: 'current' };
|
|
166
143
|
}
|
|
167
144
|
} catch (err) {
|
|
@@ -380,8 +357,8 @@ export async function backfillDelegationAddress(subId: string, address: string):
|
|
|
380
357
|
|
|
381
358
|
// Backfill the address (only if arcblock payment_details exists with required fields)
|
|
382
359
|
const existingArcblock = subscription.payment_details?.arcblock;
|
|
383
|
-
if (!existingArcblock
|
|
384
|
-
logger.
|
|
360
|
+
if (!existingArcblock) {
|
|
361
|
+
logger.info('migration: cannot backfill delegation_address - missing arcblock payment_details', {
|
|
385
362
|
subscriptionId: subscription.id,
|
|
386
363
|
});
|
|
387
364
|
return false;
|
|
@@ -3142,4 +3142,165 @@ router.post('/:id/update-stripe-payment-method', authPortal, async (req, res) =>
|
|
|
3142
3142
|
}
|
|
3143
3143
|
});
|
|
3144
3144
|
|
|
3145
|
+
/**
|
|
3146
|
+
* Fix subscription after payment method migration from Stripe to non-Stripe
|
|
3147
|
+
* This API is used to fix legacy subscriptions that were migrated but the migration
|
|
3148
|
+
* was incomplete (missing payment_settings/payment_details updates)
|
|
3149
|
+
*
|
|
3150
|
+
* This API will:
|
|
3151
|
+
* 1. Pause the Stripe subscription (if not already paused)
|
|
3152
|
+
* 2. Update payment_settings to use arcblock
|
|
3153
|
+
* 3. Update payment_details to add arcblock info
|
|
3154
|
+
* 4. Recalculate cancel_at if needed
|
|
3155
|
+
*/
|
|
3156
|
+
router.put('/:id/fix-stripe-migration', auth, async (req, res) => {
|
|
3157
|
+
try {
|
|
3158
|
+
const subscription = await Subscription.findByPk(req.params.id);
|
|
3159
|
+
if (!subscription) {
|
|
3160
|
+
return res.status(404).json({ error: 'Subscription not found' });
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
const stripeSubscriptionId = subscription.payment_details?.stripe?.subscription_id;
|
|
3164
|
+
if (!stripeSubscriptionId) {
|
|
3165
|
+
return res.status(400).json({ error: 'Subscription does not have Stripe subscription_id' });
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
// Get customer for payer DID
|
|
3169
|
+
const customer = await Customer.findByPk(subscription.customer_id);
|
|
3170
|
+
if (!customer) {
|
|
3171
|
+
return res.status(404).json({ error: 'Customer not found' });
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
// Find arcblock payment method
|
|
3175
|
+
const arcblockMethod = await PaymentMethod.findOne({
|
|
3176
|
+
where: { type: 'arcblock', livemode: subscription.livemode },
|
|
3177
|
+
});
|
|
3178
|
+
if (!arcblockMethod) {
|
|
3179
|
+
return res.status(400).json({ error: 'ArcBlock payment method not found' });
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
// Find Stripe payment method to pause subscription
|
|
3183
|
+
const stripeMethod = await PaymentMethod.findOne({
|
|
3184
|
+
where: { type: 'stripe', livemode: subscription.livemode },
|
|
3185
|
+
});
|
|
3186
|
+
|
|
3187
|
+
// 1. Pause Stripe subscription if not already paused
|
|
3188
|
+
let stripePaused = false;
|
|
3189
|
+
if (stripeMethod) {
|
|
3190
|
+
try {
|
|
3191
|
+
const client = stripeMethod.getStripeClient();
|
|
3192
|
+
const stripeSubscription = await client.subscriptions.retrieve(stripeSubscriptionId);
|
|
3193
|
+
if (stripeSubscription && !stripeSubscription.pause_collection) {
|
|
3194
|
+
await client.subscriptions.update(stripeSubscriptionId, {
|
|
3195
|
+
pause_collection: { behavior: 'void' },
|
|
3196
|
+
});
|
|
3197
|
+
stripePaused = true;
|
|
3198
|
+
logger.info('Stripe subscription paused during fix', {
|
|
3199
|
+
subscriptionId: subscription.id,
|
|
3200
|
+
stripeSubscriptionId,
|
|
3201
|
+
});
|
|
3202
|
+
} else if (stripeSubscription?.pause_collection) {
|
|
3203
|
+
logger.info('Stripe subscription already paused', {
|
|
3204
|
+
subscriptionId: subscription.id,
|
|
3205
|
+
stripeSubscriptionId,
|
|
3206
|
+
});
|
|
3207
|
+
}
|
|
3208
|
+
} catch (stripeErr) {
|
|
3209
|
+
logger.warn('Failed to pause Stripe subscription during fix, continuing anyway', {
|
|
3210
|
+
subscriptionId: subscription.id,
|
|
3211
|
+
stripeSubscriptionId,
|
|
3212
|
+
error: stripeErr,
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
|
|
3217
|
+
const updates: Partial<TSubscription> = {};
|
|
3218
|
+
|
|
3219
|
+
// 2. Update payment_settings to use arcblock (matching change-payment behavior)
|
|
3220
|
+
updates.payment_settings = {
|
|
3221
|
+
payment_method_types: ['arcblock'],
|
|
3222
|
+
payment_method_options: {
|
|
3223
|
+
arcblock: { payer: customer.did },
|
|
3224
|
+
},
|
|
3225
|
+
};
|
|
3226
|
+
|
|
3227
|
+
// 3. Update payment_details.arcblock.payer if not already present
|
|
3228
|
+
if (!subscription.payment_details?.arcblock?.payer) {
|
|
3229
|
+
const existingArcblock = subscription.payment_details?.arcblock;
|
|
3230
|
+
updates.payment_details = {
|
|
3231
|
+
...subscription.payment_details,
|
|
3232
|
+
arcblock: {
|
|
3233
|
+
...existingArcblock,
|
|
3234
|
+
payer: customer.did,
|
|
3235
|
+
type: existingArcblock?.type || 'delegate',
|
|
3236
|
+
tx_hash: existingArcblock?.tx_hash || '',
|
|
3237
|
+
},
|
|
3238
|
+
};
|
|
3239
|
+
}
|
|
3240
|
+
|
|
3241
|
+
// 4. Update default_payment_method_id to arcblock
|
|
3242
|
+
updates.default_payment_method_id = arcblockMethod.id;
|
|
3243
|
+
|
|
3244
|
+
// 5. Recalculate cancel_at if subscription has cancelation_details but no cancel_at
|
|
3245
|
+
if (req.body.recalculate_cancel_at !== false) {
|
|
3246
|
+
if (subscription.cancelation_details && !subscription.cancel_at) {
|
|
3247
|
+
const daysUntilCancel = subscription.days_until_cancel || 0;
|
|
3248
|
+
if (daysUntilCancel > 0) {
|
|
3249
|
+
const dueUnit = 24 * 60 * 60; // 1 day in seconds
|
|
3250
|
+
updates.cancel_at = subscription.current_period_start + daysUntilCancel * dueUnit;
|
|
3251
|
+
} else {
|
|
3252
|
+
updates.cancel_at_period_end = true;
|
|
3253
|
+
updates.cancel_at = subscription.current_period_end;
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
// Allow manual override of cancel_at
|
|
3259
|
+
if (typeof req.body.cancel_at === 'number') {
|
|
3260
|
+
updates.cancel_at = req.body.cancel_at;
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
await subscription.update(updates);
|
|
3264
|
+
|
|
3265
|
+
logger.info('Subscription stripe migration fixed', {
|
|
3266
|
+
subscriptionId: subscription.id,
|
|
3267
|
+
customerDid: customer.did,
|
|
3268
|
+
updates: {
|
|
3269
|
+
...updates,
|
|
3270
|
+
payment_details: '(updated)',
|
|
3271
|
+
},
|
|
3272
|
+
stripePaused,
|
|
3273
|
+
stripeSubscriptionId,
|
|
3274
|
+
});
|
|
3275
|
+
|
|
3276
|
+
// Reload subscription to return updated data
|
|
3277
|
+
await subscription.reload();
|
|
3278
|
+
|
|
3279
|
+
return res.json({
|
|
3280
|
+
success: true,
|
|
3281
|
+
stripePaused,
|
|
3282
|
+
subscription: pick(subscription, [
|
|
3283
|
+
'id',
|
|
3284
|
+
'status',
|
|
3285
|
+
'cancel_at',
|
|
3286
|
+
'cancel_at_period_end',
|
|
3287
|
+
'canceled_at',
|
|
3288
|
+
'cancelation_details',
|
|
3289
|
+
'payment_details',
|
|
3290
|
+
'payment_settings',
|
|
3291
|
+
'default_payment_method_id',
|
|
3292
|
+
'days_until_cancel',
|
|
3293
|
+
'current_period_start',
|
|
3294
|
+
'current_period_end',
|
|
3295
|
+
]),
|
|
3296
|
+
});
|
|
3297
|
+
} catch (err) {
|
|
3298
|
+
logger.error('Failed to fix subscription stripe migration', {
|
|
3299
|
+
error: err,
|
|
3300
|
+
subscriptionId: req.params.id,
|
|
3301
|
+
});
|
|
3302
|
+
return res.status(400).json({ error: err.message });
|
|
3303
|
+
}
|
|
3304
|
+
});
|
|
3305
|
+
|
|
3145
3306
|
export default router;
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.7",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"prelint": "npm run types",
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
"@blocklet/error": "^0.3.5",
|
|
60
60
|
"@blocklet/js-sdk": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
61
61
|
"@blocklet/logger": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
62
|
-
"@blocklet/payment-broker-client": "1.25.
|
|
63
|
-
"@blocklet/payment-react": "1.25.
|
|
64
|
-
"@blocklet/payment-vendor": "1.25.
|
|
62
|
+
"@blocklet/payment-broker-client": "1.25.7",
|
|
63
|
+
"@blocklet/payment-react": "1.25.7",
|
|
64
|
+
"@blocklet/payment-vendor": "1.25.7",
|
|
65
65
|
"@blocklet/sdk": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
66
66
|
"@blocklet/ui-react": "^3.4.7",
|
|
67
67
|
"@blocklet/uploader": "^0.3.19",
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"devDependencies": {
|
|
133
133
|
"@abtnode/types": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
134
134
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
135
|
-
"@blocklet/payment-types": "1.25.
|
|
135
|
+
"@blocklet/payment-types": "1.25.7",
|
|
136
136
|
"@types/cookie-parser": "^1.4.9",
|
|
137
137
|
"@types/cors": "^2.8.19",
|
|
138
138
|
"@types/debug": "^4.1.12",
|
|
@@ -179,5 +179,5 @@
|
|
|
179
179
|
"parser": "typescript"
|
|
180
180
|
}
|
|
181
181
|
},
|
|
182
|
-
"gitHead": "
|
|
182
|
+
"gitHead": "0aa950a5d3f01a150ec21c66e2efeaf81ee1cc69"
|
|
183
183
|
}
|