-
Notifications
You must be signed in to change notification settings - Fork 119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: PUT /user/payment API saves payment info in stripe.com #1818
Conversation
This reverts commit 7957f38.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job @gobengo
Did a first pass through this and left feedback. Let me know what you think
}) | ||
} | ||
}, | ||
NodeModulesPolyfillPlugin() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this for stripe? would be nice to have a comment if so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or is needed for assert?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment explaining how 'stripe' deps on some node things (though I think we dont actually import those parts, e.g. we use the Fetch http adapater instead of the Node one)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(afaict it wasn't related to the use of assert
)
@@ -35,6 +39,7 @@ import { defaultBypassMagicLinkVariableName } from './magic.link.js' | |||
* @property {string} [LOGTAIL_TOKEN] | |||
* @property {string} MAINTENANCE_MODE | |||
* @property {string} [DANGEROUSLY_BYPASS_MAGIC_AUTH] | |||
* @property {string} [STRIPE_SECRET_KEY] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is injected as a Worker secret? Can we add to https://github.com/web3-storage/web3.storage/tree/1661905101-api-tsc-and-stripe/packages/api#4-configure-your-worker secrets part?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
packages/api/src/env.js
Outdated
*/ | ||
function createStripeBillingContext (env) { | ||
const stripeSecretKey = env.STRIPE_SECRET_KEY | ||
assert.ok(stripeSecretKey, 'env STRIPE_SECRET_KEY is required') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not add assert dependency just for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure. so i can have this in mind in the future: what's the downside of the fairly-well-standardized assert dependency in this cf worker context? FWIW assert.ok
is nice because it's also a typed as a type guard. microsoft/TypeScript#32695
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assert will throw AssertionError
and in the error handler we will need to define what user error we want to send (and whether it should have 500 code or 4xx code). We could get all this with assert, but I think it would make things more complex with current code
packages/api/src/env.js
Outdated
// this can be used to mock realistic values of a stripe.com paymentMethod id | ||
// after fulls tripe integration, this may not be needed on the env | ||
env.mockStripePaymentMethodId = 'pm_1LZnQ1IfErzTm2rETa7IGoVm' | ||
Object.assign(env, (env.ENV === 'test') ? createTestBillingEnv() : createStripeBillingContext(env)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest not adding so much stripe specific logic into env file which is quite simple at the moment. So, thinking about a createStripeBillingContext(env)
factory function in utils/stripe.js
which would do this validation and have functions below. We also end up simplifying a lot the import statement here and what needs to be exported from stripe file.
What do you think @gobengo ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, wondering if we could simplify a bit this to not be so env specific. If we make STRIPE_SECRET_KEY
optional and use it as a way of identifying if we want a real billing context or a mock?
if (!env.STRIPE_SECRET_KEY) {
return {
billing: createMockBillingService(),
customers: createTestEnvCustomerService()
}
}
Probably to throw an error only as:
if (!env.STRIPE_SECRET_KEY && !(env.ENV === 'test' || env.ENV === 'dev') {
throw new Error(`Stripe secret key is required for env ${env.ENV}`)
}
thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vasco-santos great suggestion. I implemented as
475be01
3366de2
packages/api/src/user.js
Outdated
@@ -78,7 +79,7 @@ async function loginOrRegister (request, env) { | |||
|
|||
const parsed = | |||
data.type === 'github' | |||
? parseGitHub(data.data, metadata) | |||
? await parseGitHub(data.data, metadata) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not promise?
packages/api/src/utils/stripe.js
Outdated
/** | ||
* @type {BillingService} | ||
*/ | ||
const instance = this // eslint-disable-line |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the only way to have tsc check compatability with that BillingInterface
when using jsdoc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made it nicer, one line, no eslint-disable 67deec4 (also checked to make sure this new syntax gives us the same warning if the interface breaks)
packages/api/src/utils/stripe.js
Outdated
throw new Error('unable to get payment method') | ||
} | ||
if (response.deleted) { | ||
throw new Error('unexpected response.deleted') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these internal Errors or user input error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If these can happen because user input, they should be custom errors like the ones you see in src/errors.js
, otherwise they will be interpreted as 500 and throw on call alerts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(this is also the case for other Errors in this PR that I am not flagging)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vasco-santos this is not related to user error. These would be legitimately unexpected errors that might indicate something else was wrong in the stripe.com-hosted customer db. It shouldn't need to keep anyone up at night, but it would be nice to have a modest alarm (e.g. a sentry report) if these errors ever do come up, and throwing explicitly will give the debugger (probably me) a stack trace when that happens. Technically this case can happen (the type system told me), but it shouldn't, and if it does it is probably something that should be escalated to someone like us
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed these two untyped Errror
s. The first wasn't really needed. The second I added a specific CustomerNotFound
type for, and added it to the function signature so tsc helps callers be ready for it or other errors. cd82b24
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that sounds good. Thanks for details :)
async getUserCustomer (userId) { | ||
const { data, error } = await this._client | ||
.from('user_customer') | ||
.select(['customer_id'].join(',')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for the join
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
according to the docs (and tsc types, which aren't being checked in db package yet), it must be a string. https://supabase.github.io/postgrest-js/classes/PostgrestQueryBuilder.html#select
(not disagreeing that the join works now at runtime, but I'd prefer to keep it here so it doesn't have to change again if/when we enable type checking #1860 )
CREATE TABLE IF NOT EXISTS user_customer | ||
( | ||
id BIGSERIAL PRIMARY KEY, | ||
user_id BIGINT NOT NULL UNIQUE REFERENCES public.user (id), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do queries for user_id, probably we should add an index for it? What you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea! 3df2067
…ed generic Error throw)
Co-authored-by: Vasco Santos <[email protected]>
@vasco-santos Thanks for your review. I believe I addressed all of your comments. (I left an 🎉 emoji on comments I acted on). wdyt? |
I integrated some frontend work by @adamalton on top of this that actually results in a functional demo of the backend changes in this PR. It's really those changes too that we want to be deploying to staging and beyond. Let's consider this PR superceded by #1852 . @vasco-santos it's basically identical to what you reviewed already + changes based on your review. |
Motivation
Parts