A Remix & Stripe Stack, backed by Supabase (driven by Prisma), that integrates authentication, subscriptions (multi-currency, month and year intervals) and handling tier limit.
Add pino logger to normalize log output.
Use pino-pretty in dev.
Major change
I loved my {data: T, error: null} | {data: null, error: SupaStripeStackError} but it conflicts with Remix json (https://github.com/rphlmr/supa-stripe-stack/issues/7).
I know this is just a TypeScript issue for json but digging deeper I realized that it also conflicts with defer.
What happened with defer?
See this message from Remix discord.
// given a promise we want to defer
async function fetchSomethingSlow(){}
return defer({data: { fetchSomethingSlow }}) // ❌ doesn't work
return defer({fetchSomethingSlow }) // ✅ works
At this time, defer can't handle promises that are nested in an object.
So, because I want to be consistent (and reduce thinking overload when I code), I have decided to remove my pattern and to fallback to a more traditional way (try/catch/re-throw).
The global idea is:
In services, always try/catch async things and re-throw a SupaStripeStackError in the catch branch.
In loader, always try/catch services and throw a response.error in the catch branch.
In action, always try/catch services and return a response.error in the catch branch.
Throwing a response.error should be handled in a CatchBoundary or it will be bubbled and caught by Remix top-level ErrorBoundary (the red stack trace thing that is shown instead of your component).
Returning a response.error gives you the possibility to handle it in the component instead of CatchBoundary (like in a toaster, notification, etc).
Note: if you return response.error in the catch branch, then, in useActionData/useLoaderData, you will have a props error that contains message.
Until you check the presence of error, TypeScript intellisense will tell you that there is nothing else. (this is NOT a bug ;) )
This is because you have to make something with error before accessing data that comes when there is no error.
It forces you to handle the possible error.
Add pino logger to normalize log output. Use pino-pretty in dev.
Major change
I loved my
{data: T, error: null} | {data: null, error: SupaStripeStackError}
but it conflicts with Remixjson
(https://github.com/rphlmr/supa-stripe-stack/issues/7). I know this is just a TypeScript issue forjson
but digging deeper I realized that it also conflicts withdefer
.What happened with
defer
? See this message from Remix discord.At this time,
defer
can't handle promises that are nested in an object.So, because I want to be consistent (and reduce thinking overload when I code), I have decided to remove my pattern and to fallback to a more traditional way (try/catch/re-throw).
The global idea is:
SupaStripeStackError
in the catch branch.response.error
in the catch branch.response.error
in the catch branch.Throwing a
response.error
should be handled in a CatchBoundary or it will be bubbled and caught by Remix top-level ErrorBoundary (the red stack trace thing that is shown instead of your component).Returning a
response.error
gives you the possibility to handle it in the component instead of CatchBoundary (like in a toaster, notification, etc).Note: if you return
response.error
in the catch branch, then, inuseActionData
/useLoaderData
, you will have a propserror
that containsmessage
. Until you check the presence oferror
, TypeScript intellisense will tell you that there is nothing else. (this is NOT a bug ;) ) This is because you have to make something witherror
before accessing data that comes when there is no error. It forces you to handle the possible error.