Skip to content

Commit

Permalink
feat: extract ids from namespaced object
Browse files Browse the repository at this point in the history
  • Loading branch information
stfsy committed Nov 26, 2022
1 parent d213d48 commit 66de639
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 14 deletions.
37 changes: 31 additions & 6 deletions lib/subscription-hook-storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ class Subscriptions {
return 'INVALID_ARGUMENTS'
}

static get ERROR_INVALID_PASSTHROUGH() {
return 'INVALID_PASSTHROUGH'
}

/**
* Adds a placeholder for a subscription so that webhooks only need to append to existing subscription
*
Expand Down Expand Up @@ -144,7 +148,7 @@ class Subscriptions {
return Promise.reject(new Error(this.ERROR_INVALID_ARGUMENTS))
}

const { ids } = JSON.parse(subscription.passthrough)
const ids = this._getTargetIdsFromPassthrough(subscription.passthrough)

const statusModel = {
alert_id: subscription.alert_id,
Expand Down Expand Up @@ -172,6 +176,27 @@ class Subscriptions {
await this._storage.update(ids, flatModel)
}

_getTargetIdsFromPassthrough(passthrough) {
if (!passthrough) {
console.log(`Received invalid falsy object in passthrough._pi. Actual passthrough value was ${JSON.stringify(passthrough)}. Please pass a valid object during checkout`)
throw new Error(Subscriptions.ERROR_INVALID_PASSTHROUGH)
}

const { _pi: paddleIntegration } = JSON.parse(passthrough)
if (!paddleIntegration) {
console.log(`Received invalid falsy object in passthrough._pi. Actual passthrough value was ${JSON.stringify(passthrough)}. Please pass a valid object during checkout`)
throw new Error(Subscriptions.ERROR_INVALID_PASSTHROUGH)
}

const { ids: targetIds } = paddleIntegration
if (!Array.isArray(targetIds) && targetIds.length < 1) {
console.log('Received invalid falsy array in passthrough._pi.ids. Please pass a valid object during checkout')
throw new Error(Subscriptions.ERROR_INVALID_PASSTHROUGH)
}

return targetIds
}

/**
* Add an subscription updated event. Uses the `passthrough` parameter to identify the target subscription.
*
Expand All @@ -196,7 +221,7 @@ class Subscriptions {
}
))

const { ids } = JSON.parse(subscription.passthrough)
const ids = this._getTargetIdsFromPassthrough(subscription.passthrough)

const statusModel = {
alert_id: subscription.alert_id,
Expand Down Expand Up @@ -235,7 +260,7 @@ class Subscriptions {
return Promise.reject(new Error(this.ERROR_INVALID_ARGUMENTS))
}

const { ids } = JSON.parse(subscription.passthrough)
const ids = this._getTargetIdsFromPassthrough(subscription.passthrough)

const statusModel = {
alert_id: subscription.alert_id,
Expand Down Expand Up @@ -272,7 +297,7 @@ class Subscriptions {
return Promise.reject(new Error(this.ERROR_INVALID_ARGUMENTS))
}

const { ids } = JSON.parse(payment.passthrough)
const ids = this._getTargetIdsFromPassthrough(payment.passthrough)

const encoded = htmlEncode(payment)
delete encoded.p_signature
Expand All @@ -298,7 +323,7 @@ class Subscriptions {
return Promise.reject(new Error(this.ERROR_INVALID_ARGUMENTS))
}

const { ids } = JSON.parse(payment.passthrough)
const ids = this._getTargetIdsFromPassthrough(payment.passthrough)

const encoded = htmlEncode(payment)
delete encoded.p_signature
Expand All @@ -324,7 +349,7 @@ class Subscriptions {
return Promise.reject(new Error(this.ERROR_INVALID_ARGUMENTS))
}

const { ids } = JSON.parse(payment.passthrough)
const ids = this._getTargetIdsFromPassthrough(payment.passthrough)

const encoded = htmlEncode(payment)
delete encoded.p_signature
Expand Down
21 changes: 19 additions & 2 deletions lib/subscription-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ class SubscriptionInfo {
// use the ids from paddle api here
// these were initially passed during checkout and cannot be updated
// thus we ensure that user do not hydrate other subscriptions too
passthrough: JSON.stringify({ ids: idsFromCustomData })
passthrough: JSON.stringify({ '_pi': { ids: idsFromCustomData } })
}

if (subscription.state === 'active') {
Expand Down Expand Up @@ -540,7 +540,24 @@ class SubscriptionInfo {
return
}

// more sanity checks here
const subscription = subscriptions.at(0)
if (!subscription.custom_data?._pi?.ids) {
console.error(`Expected "subscription.custom_data._pi.ids" to be an Array. Did you set customData during Checkout? Please see https://developer.paddle.com/changelog/e9a54055ea46e-custom-data-now-available#custom-data-in-webhooks.`)
throw new Error(SubscriptionInfo.HYDRATION_BAD_REQUEST)
}

const idsFromCustomData = subscription.custom_data._pi.ids
if (!Array.isArray(idsFromCustomData)) {
console.error(`Expected "subscription.custom_data._pi.ids" to be an Array. Did you set customData during Checkout? Please see https://developer.paddle.com/changelog/e9a54055ea46e-custom-data-now-available#custom-data-in-webhooks.`)
throw new Error(SubscriptionInfo.HYDRATION_UNAUTHORIZED)
}

const isForTargetId = ids.length === idsFromCustomData.length && idsFromCustomData.every((id, index) => id === ids[index])
if (!isForTargetId) {
console.error(`Expected "subscription.custom_data._pi.ids" ${isForTargetId} to deep equal ids given via parameter ${ids}.`)
throw new Error(SubscriptionInfo.HYDRATION_UNAUTHORIZED)
}

const hookPayload = {
alert_id: SubscriptionInfo.HYDRATION_SUBSCRIPTION_CANCELLED,
Expand All @@ -556,7 +573,7 @@ class SubscriptionInfo {
cancel_url: subscription.cancel_url,
checkout_id: checkoutId,
user_id: subscription.user_id,
passthrough: JSON.stringify({ ids })
passthrough: JSON.stringify({ '_pi': { ids: idsFromCustomData } })
}

if (subscription.state === 'deleted') {
Expand Down
15 changes: 9 additions & 6 deletions test-e2e/test-page/fragments/checkout/checkout-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ <h2 class="text-3xl text-center">
}
}
})

const passthrough = {
_pi: {
ids: [clientId]
}
}

Paddle.Checkout.open({
method: 'inline',
// product: 649915, // Replace with your Product or Plan ID
Expand All @@ -160,14 +167,10 @@ <h2 class="text-3xl text-center">
email: 'a@b.com',
title: 'This is the title',
message: 'This is a message',
customData: {
_pi: {
ids: [clientId]
}
},
customData: passthrough,
allowQuantity: false,
disableLogout: false,
passthrough: `{"ids": ["${clientId}"]}`,
passthrough,
frameTarget: 'paddle', // The className of your checkout <div>
frameInitialHeight: 500,
frameStyle: 'position: relative;', // Please ensure the minimum width is kept at or above 286px with checkout padding disabled, or 312px with checkout padding enabled. See "General" section under "Branded Inline Checkout" below for more information on checkout padding.
Expand Down

0 comments on commit 66de639

Please sign in to comment.