-
-
Sign up for this amazing SaaS right now - don't miss out!
-
-
-
+{#if session !== null}
+
+ Welcome back {session.user.email}
+
+{:else}
+
+
+
+
+ Sign up for this amazing SaaS right now - don't miss out!
+
+
+
+
+
-
+{/if}
Date: Tue, 10 Sep 2024 20:54:59 +0100
Subject: [PATCH 3/5] feat(#29): Add additional stripe webhook event handlers
---
src/routes/api/webhook/stripe/+server.ts | 31 ++++++++++--------------
1 file changed, 13 insertions(+), 18 deletions(-)
diff --git a/src/routes/api/webhook/stripe/+server.ts b/src/routes/api/webhook/stripe/+server.ts
index 7370213..eb79fd8 100644
--- a/src/routes/api/webhook/stripe/+server.ts
+++ b/src/routes/api/webhook/stripe/+server.ts
@@ -1,7 +1,7 @@
import type { RequestHandler } from '@sveltejs/kit';
import stripe from 'stripe';
-import { PUBLIC_STRIPE_SECRET_KEY } from '$env/static/public';
-import { PUBLIC_STRIPE_ENDPOINT_SECRET } from '$env/static/public';
+import { STRIPE_SECRET_KEY } from '$env/static/private';
+import { STRIPE_ENDPOINT_SECRET } from '$env/static/private';
import {
deletePriceRecord,
deleteProductRecord,
@@ -10,7 +10,7 @@ import {
upsertProductRecord
} from '$lib/utils/supabase/admin';
-const stripeClient = new stripe(PUBLIC_STRIPE_SECRET_KEY);
+const stripeClient = new stripe(STRIPE_SECRET_KEY);
export const POST: RequestHandler = async ({ request }) => {
const body = await request.text();
@@ -23,13 +23,9 @@ export const POST: RequestHandler = async ({ request }) => {
// Only verify the event if you have an endpoint secret defined.
// Otherwise use the basic event deserialized with JSON.parse
- if (PUBLIC_STRIPE_ENDPOINT_SECRET && signature) {
+ if (STRIPE_ENDPOINT_SECRET && signature) {
try {
- event = stripeClient.webhooks.constructEvent(
- body,
- signature,
- PUBLIC_STRIPE_ENDPOINT_SECRET
- );
+ event = stripeClient.webhooks.constructEvent(body, signature, STRIPE_ENDPOINT_SECRET);
} catch (err) {
console.error(`⚠️ Webhook signature verification failed.`, err.message);
return {
@@ -44,6 +40,9 @@ export const POST: RequestHandler = async ({ request }) => {
case 'product.updated':
await upsertProductRecord(event.data.object as stripe.Product);
break;
+ case 'product.deleted':
+ await deleteProductRecord(event.data.object as stripe.Product);
+ break;
case 'price.created':
case 'price.updated':
await upsertPriceRecord(event.data.object as stripe.Price);
@@ -51,12 +50,11 @@ export const POST: RequestHandler = async ({ request }) => {
case 'price.deleted':
await deletePriceRecord(event.data.object as stripe.Price);
break;
- case 'product.deleted':
- await deleteProductRecord(event.data.object as stripe.Product);
- break;
case 'customer.subscription.created':
case 'customer.subscription.updated':
- case 'customer.subscription.deleted': {
+ case 'customer.subscription.deleted':
+ case 'customer.subscription.paused':
+ case 'customer.subscription.resumed': {
const subscription = event.data.object as stripe.Subscription;
await manageSubscriptionStatusChange(
subscription.id,
@@ -86,10 +84,7 @@ export const POST: RequestHandler = async ({ request }) => {
status: 200
});
} catch (err) {
- console.log(`Webhook Error: ${err.message}`);
- return {
- status: 400,
- body: `Webhook Error: ${err.message}`
- };
+ const message = err instanceof Error ? err.message : 'An unknown error has occurred';
+ return new Response(`Webhook Error: ${message}`, { status: 500 });
}
};
From b365d77c16ae3459e9c6018e787a66997184d728 Mon Sep 17 00:00:00 2001
From: Josh Creek <8179928+jcreek@users.noreply.github.com>
Date: Tue, 10 Sep 2024 21:25:44 +0100
Subject: [PATCH 4/5] feat(#29): Handle upserting new fields for products and
prices
---
src/lib/utils/supabase/admin.ts | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/lib/utils/supabase/admin.ts b/src/lib/utils/supabase/admin.ts
index a5a53eb..874255b 100644
--- a/src/lib/utils/supabase/admin.ts
+++ b/src/lib/utils/supabase/admin.ts
@@ -31,8 +31,11 @@ const upsertProductRecord = async (product: stripe.Product) => {
active: product.active,
name: product.name,
description: product.description ?? null,
- image: product.images?.[0] ?? null,
- metadata: product.metadata
+ features: product.marketing_features.map(({ name }) => name || '').filter((name) => !!name),
+ images: product.images ?? null,
+ metadata: product.metadata,
+ created: new Date(product.created * 1000).toISOString(),
+ updated: new Date(product.updated * 1000).toISOString()
};
const { error: upsertError } = await supabaseAdmin.from('products').upsert([productData]);
@@ -46,6 +49,8 @@ const upsertPriceRecord = async (price: stripe.Price, retryCount = 0, maxRetries
product_id: typeof price.product === 'string' ? price.product : '',
active: price.active,
currency: price.currency,
+ description: price.nickname ?? null,
+ metadata: price.metadata,
type: price.type,
unit_amount: price.unit_amount ?? null,
interval: price.recurring?.interval ?? null,
From 7e0c06bab3f5b4e1ee975151f09372cada151c23 Mon Sep 17 00:00:00 2001
From: Josh Creek <8179928+jcreek@users.noreply.github.com>
Date: Tue, 10 Sep 2024 21:47:46 +0100
Subject: [PATCH 5/5] fix(#29): Ensure updating subscription works properly
---
src/lib/utils/supabase/admin.ts | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/src/lib/utils/supabase/admin.ts b/src/lib/utils/supabase/admin.ts
index 874255b..6a774d6 100644
--- a/src/lib/utils/supabase/admin.ts
+++ b/src/lib/utils/supabase/admin.ts
@@ -213,9 +213,7 @@ const manageSubscriptionStatusChange = async (
metadata: subscription.metadata,
status: subscription.status,
price_id: subscription.items.data[0].price.id,
- //TODO check quantity on subscription
-
- quantity: subscription.quantity,
+ quantity: 1, //subscription.quantity,
cancel_at_period_end: subscription.cancel_at_period_end,
cancel_at: subscription.cancel_at ? toDateTime(subscription.cancel_at).toISOString() : null,
canceled_at: subscription.canceled_at
@@ -237,13 +235,14 @@ const manageSubscriptionStatusChange = async (
if (upsertError) throw new Error(`Subscription insert/update failed: ${upsertError.message}`);
console.log(`Inserted/updated subscription [${subscription.id}] for user [${uuid}]`);
- // For a new subscription copy the billing details to the customer object.
- // NOTE: This is a costly operation and should happen at the very end.
- if (createAction && subscription.default_payment_method && uuid)
- await copyBillingDetailsToCustomer(
- uuid,
- subscription.default_payment_method as stripe.PaymentMethod
- );
+ // // For a new subscription copy the billing details to the customer object.
+ // // NOTE: This is a costly operation and should happen at the very end.
+ // if (createAction && subscription.default_payment_method && uuid) {
+ // await copyBillingDetailsToCustomer(
+ // uuid,
+ // subscription.default_payment_method as stripe.PaymentMethod
+ // );
+ // }
};
export {