@dotted-labs/ngx-supabase-stripe 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,6 +24,11 @@ function provideStripeConfig(config) {
24
24
  ];
25
25
  }
26
26
 
27
+ /**
28
+ * Optional shared browser `SupabaseClient` (e.g. the same instance passed to ngx-supabase-auth).
29
+ * When provided, {@link SupabaseClientService} uses it instead of creating a new client.
30
+ */
31
+ const SUPABASE_BROWSER_CLIENT = new InjectionToken('SUPABASE_BROWSER_CLIENT');
27
32
  const SUPABASE_CONFIG = new InjectionToken('SUPABASE_CONFIG');
28
33
  /**
29
34
  * Provides the Supabase configuration
@@ -60,9 +65,12 @@ function provideNgxSupabaseStripeConfig(config) {
60
65
 
61
66
  class SupabaseClientService {
62
67
  config = inject(SUPABASE_CONFIG);
68
+ browserClient = inject(SUPABASE_BROWSER_CLIENT, { optional: true });
63
69
  client;
64
70
  constructor() {
65
- this.client = createClient(this.config.supabaseUrl, this.config.supabaseKey);
71
+ this.client =
72
+ this.browserClient ??
73
+ createClient(this.config.supabaseUrl, this.config.supabaseKey);
66
74
  console.log('🚀 [SupabaseClientService]: this.client', this.client);
67
75
  }
68
76
  /**
@@ -324,6 +332,48 @@ class StripeClientService {
324
332
  this.stripe = loadStripe(this.config.publishableKey);
325
333
  console.log('🔌 [StripeClientService]: Loaded Stripe Client from @stripe/stripe-js');
326
334
  }
335
+ /**
336
+ * Edge functions use JWT verification (e.g. getClaims). Requires a logged-in Supabase Auth user.
337
+ */
338
+ async resolveFunctionsAuth() {
339
+ const client = this.supabase.getClient();
340
+ const { data: sessionData, error: sessionError } = await client.auth.getSession();
341
+ if (sessionError) {
342
+ return { ok: false, error: new Error(sessionError.message) };
343
+ }
344
+ let accessToken = sessionData.session?.access_token;
345
+ if (!accessToken) {
346
+ const { data: refreshed, error: refreshError } = await client.auth.refreshSession();
347
+ if (refreshError) {
348
+ return { ok: false, error: new Error(refreshError.message) };
349
+ }
350
+ accessToken = refreshed.session?.access_token;
351
+ }
352
+ if (!accessToken) {
353
+ return {
354
+ ok: false,
355
+ error: new Error('No Supabase Auth session. Sign in before checkout (e.g. signInWithPassword, signInWithOAuth, or magic link).'),
356
+ };
357
+ }
358
+ return { ok: true, headers: { Authorization: `Bearer ${accessToken}` } };
359
+ }
360
+ async invokeWithAuth(name, options = {}) {
361
+ const auth = await this.resolveFunctionsAuth();
362
+ if (!auth.ok) {
363
+ return { data: null, error: auth.error };
364
+ }
365
+ const { data, error } = await this.supabase.getClient().functions.invoke(name, {
366
+ ...options,
367
+ headers: {
368
+ ...options.headers,
369
+ ...auth.headers,
370
+ },
371
+ });
372
+ if (error) {
373
+ return { data: null, error: error };
374
+ }
375
+ return { data, error: null };
376
+ }
327
377
  /**
328
378
  * Get the Stripe instance
329
379
  */
@@ -373,20 +423,19 @@ class StripeClientService {
373
423
  */
374
424
  async createCheckoutSession(priceId, resultPagePath, customer) {
375
425
  try {
376
- const { data, error } = await this.supabase.getClient()
377
- .functions.invoke('checkout_session', {
426
+ const { data, error } = await this.invokeWithAuth('checkout_session', {
378
427
  body: {
379
428
  priceId,
380
429
  resultPagePath,
381
- customer
382
- }
430
+ customer,
431
+ },
383
432
  });
384
433
  if (error) {
385
434
  throw error;
386
435
  }
387
436
  return {
388
437
  clientSecret: data?.client_secret ?? null,
389
- error: null
438
+ error: null,
390
439
  };
391
440
  }
392
441
  catch (error) {
@@ -399,13 +448,12 @@ class StripeClientService {
399
448
  */
400
449
  async createSubscription(priceId, returnPath, customer) {
401
450
  try {
402
- const { data, error } = await this.supabase.getClient()
403
- .functions.invoke('create_subscription', {
451
+ const { data, error } = await this.invokeWithAuth('create_subscription', {
404
452
  body: {
405
453
  priceId,
406
454
  resultPagePath: returnPath,
407
- customer
408
- }
455
+ customer,
456
+ },
409
457
  });
410
458
  if (error) {
411
459
  throw error;
@@ -423,12 +471,11 @@ class StripeClientService {
423
471
  */
424
472
  async updateSubscription(subscriptionId, params) {
425
473
  try {
426
- const { data, error } = await this.supabase.getClient()
427
- .functions.invoke('update_subscription', {
474
+ const { data, error } = await this.invokeWithAuth('update_subscription', {
428
475
  body: {
429
476
  subscriptionId,
430
- params
431
- }
477
+ params,
478
+ },
432
479
  });
433
480
  if (error) {
434
481
  throw error;
@@ -445,11 +492,10 @@ class StripeClientService {
445
492
  */
446
493
  async getSubscription(subscriptionId) {
447
494
  try {
448
- const { data, error } = await this.supabase.getClient()
449
- .functions.invoke('get_subscription', {
495
+ const { data, error } = await this.invokeWithAuth('get_subscription', {
450
496
  body: {
451
- subscriptionId
452
- }
497
+ subscriptionId,
498
+ },
453
499
  });
454
500
  if (error) {
455
501
  throw error;
@@ -465,8 +511,7 @@ class StripeClientService {
465
511
  */
466
512
  async listSubscriptions() {
467
513
  try {
468
- const { data, error } = await this.supabase.getClient()
469
- .functions.invoke('list_subscriptions');
514
+ const { data, error } = await this.invokeWithAuth('list_subscriptions');
470
515
  if (error) {
471
516
  throw error;
472
517
  }
@@ -482,11 +527,10 @@ class StripeClientService {
482
527
  */
483
528
  async cancelSubscription(subscriptionId) {
484
529
  try {
485
- const { data, error } = await this.supabase.getClient()
486
- .functions.invoke('cancel_subscription', {
530
+ const { data, error } = await this.invokeWithAuth('cancel_subscription', {
487
531
  body: {
488
- subscriptionId
489
- }
532
+ subscriptionId,
533
+ },
490
534
  });
491
535
  if (error) {
492
536
  throw error;
@@ -504,12 +548,11 @@ class StripeClientService {
504
548
  */
505
549
  async resumeSubscription(subscriptionId, params) {
506
550
  try {
507
- const { data, error } = await this.supabase.getClient()
508
- .functions.invoke('resume_subscription', {
551
+ const { data, error } = await this.invokeWithAuth('resume_subscription', {
509
552
  body: {
510
553
  subscriptionId,
511
- params
512
- }
554
+ params,
555
+ },
513
556
  });
514
557
  if (error) {
515
558
  throw error;
@@ -526,11 +569,10 @@ class StripeClientService {
526
569
  */
527
570
  async getCheckoutSessionStatus(sessionId) {
528
571
  try {
529
- const { data, error } = await this.supabase.getClient()
530
- .functions.invoke('session_status', {
572
+ const { data, error } = await this.invokeWithAuth('session_status', {
531
573
  body: {
532
- sessionId
533
- }
574
+ sessionId,
575
+ },
534
576
  });
535
577
  if (error) {
536
578
  throw error;
@@ -549,12 +591,11 @@ class StripeClientService {
549
591
  */
550
592
  async createPortalSession(customerId, returnUrl) {
551
593
  try {
552
- const { data, error } = await this.supabase.getClient()
553
- .functions.invoke('create_portal_session', {
594
+ const { data, error } = await this.invokeWithAuth('create_portal_session', {
554
595
  body: {
555
596
  customerId,
556
- returnUrl
557
- }
597
+ returnUrl,
598
+ },
558
599
  });
559
600
  if (error) {
560
601
  throw error;
@@ -571,11 +612,10 @@ class StripeClientService {
571
612
  */
572
613
  async createCustomer(customerEmail) {
573
614
  try {
574
- const { data, error } = await this.supabase.getClient()
575
- .functions.invoke('create_customer', {
615
+ const { data, error } = await this.invokeWithAuth('create_customer', {
576
616
  body: {
577
- customerEmail
578
- }
617
+ customerEmail,
618
+ },
579
619
  });
580
620
  if (error) {
581
621
  throw error;
@@ -588,9 +628,8 @@ class StripeClientService {
588
628
  }
589
629
  async getCustomerPaymentMethods(customerId) {
590
630
  try {
591
- const { data, error } = await this.supabase.getClient()
592
- .functions.invoke('customer_payment_methods', {
593
- body: { customerId }
631
+ const { data, error } = await this.invokeWithAuth('customer_payment_methods', {
632
+ body: { customerId },
594
633
  });
595
634
  if (error) {
596
635
  throw error;
@@ -603,9 +642,8 @@ class StripeClientService {
603
642
  }
604
643
  async getCustomerPaymentMethod(customerId, paymentMethodId) {
605
644
  try {
606
- const { data, error } = await this.supabase.getClient()
607
- .functions.invoke('customer_payment_method', {
608
- body: { customerId, paymentMethodId }
645
+ const { data, error } = await this.invokeWithAuth('customer_payment_method', {
646
+ body: { customerId, paymentMethodId },
609
647
  });
610
648
  if (error) {
611
649
  throw error;
@@ -1320,6 +1358,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1320
1358
  class EmbeddedCheckoutComponent {
1321
1359
  checkoutStore = inject(CheckoutStore);
1322
1360
  customerStore = inject(CustomerStore);
1361
+ stripeConfig = inject(STRIPE_CONFIG);
1323
1362
  priceId = input.required(...(ngDevMode ? [{ debugName: "priceId" }] : []));
1324
1363
  returnPagePath = input('/return', ...(ngDevMode ? [{ debugName: "returnPagePath" }] : []));
1325
1364
  customer = computed(() => this.customerStore.customer().data, ...(ngDevMode ? [{ debugName: "customer" }] : []));
@@ -1327,8 +1366,10 @@ class EmbeddedCheckoutComponent {
1327
1366
  this.createCheckoutSession();
1328
1367
  }
1329
1368
  createCheckoutSession() {
1330
- const baseUrl = window.location.origin;
1331
- const returnPath = `${baseUrl}${this.returnPagePath()}`;
1369
+ const base = (this.stripeConfig.embeddedCheckoutBaseUrl?.trim() ||
1370
+ (typeof window !== 'undefined' ? window.location.origin : '')).replace(/\/$/, '');
1371
+ const path = this.returnPagePath();
1372
+ const returnPath = path.startsWith('/') ? `${base}${path}` : `${base}/${path}`;
1332
1373
  // Create the checkout session
1333
1374
  this.checkoutStore.createCheckoutSession({
1334
1375
  priceId: this.priceId(),
@@ -1527,6 +1568,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1527
1568
  class EmbeddedSubscriptionComponent {
1528
1569
  subscriptionsStore = inject(SubscriptionsStore);
1529
1570
  customerStore = inject(CustomerStore);
1571
+ stripeConfig = inject(STRIPE_CONFIG);
1530
1572
  priceId = input.required(...(ngDevMode ? [{ debugName: "priceId" }] : []));
1531
1573
  returnPagePath = input('/subscription-return', ...(ngDevMode ? [{ debugName: "returnPagePath" }] : []));
1532
1574
  customer = computed(() => this.customerStore.customer().data, ...(ngDevMode ? [{ debugName: "customer" }] : []));
@@ -1534,8 +1576,10 @@ class EmbeddedSubscriptionComponent {
1534
1576
  this.createSubscription();
1535
1577
  }
1536
1578
  createSubscription() {
1537
- const baseUrl = window.location.origin;
1538
- const returnPath = `${baseUrl}${this.returnPagePath()}`;
1579
+ const base = (this.stripeConfig.embeddedCheckoutBaseUrl?.trim() ||
1580
+ (typeof window !== 'undefined' ? window.location.origin : '')).replace(/\/$/, '');
1581
+ const path = this.returnPagePath();
1582
+ const returnPath = path.startsWith('/') ? `${base}${path}` : `${base}/${path}`;
1539
1583
  this.subscriptionsStore.createSubscription(this.priceId(), returnPath, this.customer());
1540
1584
  }
1541
1585
  ngOnDestroy() {
@@ -2005,5 +2049,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2005
2049
  * Generated bundle index. Do not edit.
2006
2050
  */
2007
2051
 
2008
- export { CheckoutStore, Currency, CustomerDashboardComponent, CustomerStore, EmbeddedCheckoutComponent, EmbeddedSubscriptionComponent, PaymentIntentsListComponent, PaymentIntentsTableComponent, PortalAccountStore, ProductItemButtonComponent, ProductListComponent, ProductsStore, ReturnPageComponent, STRIPE_CONFIG, SUPABASE_CONFIG, StripeClientService, SubscriptionCardComponent, SubscriptionReturnPageComponent, SubscriptionsListComponent, SubscriptionsStore, SupabaseClientService, parsePaymentIntent, parseProduct, parseSubscription, provideNgxSupabaseStripeConfig, provideStripeConfig, provideSupabaseConfig };
2052
+ export { CheckoutStore, Currency, CustomerDashboardComponent, CustomerStore, EmbeddedCheckoutComponent, EmbeddedSubscriptionComponent, PaymentIntentsListComponent, PaymentIntentsTableComponent, PortalAccountStore, ProductItemButtonComponent, ProductListComponent, ProductsStore, ReturnPageComponent, STRIPE_CONFIG, SUPABASE_BROWSER_CLIENT, SUPABASE_CONFIG, StripeClientService, SubscriptionCardComponent, SubscriptionReturnPageComponent, SubscriptionsListComponent, SubscriptionsStore, SupabaseClientService, parsePaymentIntent, parseProduct, parseSubscription, provideNgxSupabaseStripeConfig, provideStripeConfig, provideSupabaseConfig };
2009
2053
  //# sourceMappingURL=dotted-labs-ngx-supabase-stripe.mjs.map