diff --git a/src/lib/utils/supabase/admin.ts b/src/lib/utils/supabase/admin.ts index a5a53eb..6a774d6 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, @@ -208,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 @@ -232,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 { diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 136c686..f0db6cd 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -6,16 +6,24 @@ $: ({ supabase, session } = data); -
-
-
-

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}
{ 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 }); } }; diff --git a/tsconfig.json b/tsconfig.json index c545d33..611f6e4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ "moduleResolution": "bundler", "module": "es2015" }, - "include": ["src/**/*", "node_modules/**/*.d.ts"] + "include": ["src/**/*", "node_modules/**/*.d.ts", ".svelte-kit/ambient.d.ts"] // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes