stripe-no-webhooks 0.0.4 → 0.0.6

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.
package/bin/cli.js CHANGED
@@ -413,134 +413,154 @@ function findMatchingBrace(content, startIndex) {
413
413
  return -1;
414
414
  }
415
415
 
416
- function parseBillingConfig(content) {
417
- // Extract the plans array from the file content
418
- const plansStartMatch = content.match(/plans\s*:\s*\[/);
419
- if (!plansStartMatch) {
420
- return [];
416
+ function getMode(stripeKey) {
417
+ if (stripeKey.includes("_test_")) {
418
+ return "test";
419
+ } else if (stripeKey.includes("_live_")) {
420
+ return "production";
421
+ } else {
422
+ throw new Error("Invalid Stripe key");
421
423
  }
424
+ }
422
425
 
423
- const plansStart = plansStartMatch.index + plansStartMatch[0].length - 1;
424
- const plansEnd = findMatchingBrace(content, plansStart);
425
- if (plansEnd === -1) return [];
426
-
427
- const plansContent = content.substring(plansStart + 1, plansEnd);
428
- const plans = [];
426
+ function tsObjectToJson(tsContent) {
427
+ // Remove single-line comments
428
+ let json = tsContent.replace(/\/\/.*$/gm, "");
429
+ // Remove multi-line comments
430
+ json = json.replace(/\/\*[\s\S]*?\*\//g, "");
431
+ // Quote unquoted keys (word characters followed by colon)
432
+ json = json.replace(/(\s*)(\w+)(\s*:)/g, '$1"$2"$3');
433
+ // Remove trailing commas before ] or }
434
+ json = json.replace(/,(\s*[}\]])/g, "$1");
435
+ return json;
436
+ }
429
437
 
430
- // Find each plan object by looking for opening braces at the top level
431
- let depth = 0;
432
- let planStart = -1;
433
-
434
- for (let i = 0; i < plansContent.length; i++) {
435
- const char = plansContent[i];
436
- if (char === "{") {
437
- if (depth === 0) planStart = i;
438
- depth++;
439
- } else if (char === "}") {
440
- depth--;
441
- if (depth === 0 && planStart !== -1) {
442
- const planRaw = plansContent.substring(planStart, i + 1);
443
- const plan = parsePlanObject(planRaw);
444
- if (plan.name) {
445
- plans.push({
446
- plan,
447
- raw: planRaw,
448
- startIndex:
449
- plansStartMatch.index + plansStartMatch[0].length + planStart,
450
- });
451
- }
452
- planStart = -1;
453
- }
454
- }
438
+ function extractBillingConfigObject(content) {
439
+ // Find the start of the config object
440
+ const configStartMatch = content.match(
441
+ /const\s+billingConfig\s*:\s*BillingConfig\s*=\s*\{/
442
+ );
443
+ if (!configStartMatch) {
444
+ return null;
455
445
  }
456
446
 
457
- return plans;
447
+ const objectStart = configStartMatch.index + configStartMatch[0].length - 1;
448
+ const objectEnd = findMatchingBrace(content, objectStart);
449
+ if (objectEnd === -1) return null;
450
+
451
+ const rawObject = content.substring(objectStart, objectEnd + 1);
452
+ return {
453
+ raw: rawObject,
454
+ start: objectStart,
455
+ end: objectEnd + 1,
456
+ };
458
457
  }
459
458
 
460
- function parsePlanObject(planContent) {
461
- const plan = {};
462
-
463
- // Extract id if present (product id)
464
- const idMatch = planContent.match(/^\s*\{\s*id\s*:\s*["']([^"']+)["']/);
465
- if (idMatch) plan.id = idMatch[1];
466
-
467
- // Also try to find id not at start
468
- if (!plan.id) {
469
- const idMatch2 = planContent.match(/[,{]\s*id\s*:\s*["']([^"']+)["']/);
470
- if (idMatch2) plan.id = idMatch2[1];
471
- }
472
-
473
- // Extract name
474
- const nameMatch = planContent.match(/name\s*:\s*["']([^"']+)["']/);
475
- if (nameMatch) plan.name = nameMatch[1];
476
-
477
- // Extract description
478
- const descMatch = planContent.match(/description\s*:\s*["']([^"']+)["']/);
479
- if (descMatch) plan.description = descMatch[1];
480
-
481
- // Extract price array
482
- const priceStartMatch = planContent.match(/price\s*:\s*\[/);
483
- if (priceStartMatch) {
484
- const priceStart = priceStartMatch.index + priceStartMatch[0].length - 1;
485
- const priceEnd = findMatchingBrace(planContent, priceStart);
486
- if (priceEnd !== -1) {
487
- const priceArrayContent = planContent.substring(priceStart + 1, priceEnd);
488
- plan.prices = parsePriceArray(priceArrayContent);
489
- plan.priceArrayStart = priceStart;
490
- plan.priceArrayEnd = priceEnd;
491
- }
459
+ function parseBillingConfig(content, mode) {
460
+ const extracted = extractBillingConfigObject(content);
461
+ if (!extracted) {
462
+ return { config: null, plans: [] };
492
463
  }
493
464
 
494
- return plan;
465
+ // Convert to JSON and parse
466
+ const jsonString = tsObjectToJson(extracted.raw);
467
+ let config;
468
+ try {
469
+ config = JSON.parse(jsonString);
470
+ } catch (e) {
471
+ console.error("Failed to parse billing config as JSON:", e.message);
472
+ return { config: null, plans: [] };
473
+ }
474
+
475
+ // Get plans for the specified mode
476
+ const modeConfig = config[mode];
477
+ if (!modeConfig || !modeConfig.plans || modeConfig.plans.length === 0) {
478
+ return { config, plans: [], extracted };
479
+ }
480
+
481
+ // Return parsed plans with their indices for updating
482
+ const plans = modeConfig.plans.map((plan, index) => ({
483
+ plan,
484
+ index,
485
+ }));
486
+
487
+ return { config, plans, extracted };
495
488
  }
496
489
 
497
- function parsePriceArray(priceArrayContent) {
498
- const prices = [];
499
- let depth = 0;
500
- let priceStart = -1;
501
-
502
- for (let i = 0; i < priceArrayContent.length; i++) {
503
- const char = priceArrayContent[i];
504
- if (char === "{") {
505
- if (depth === 0) priceStart = i;
506
- depth++;
507
- } else if (char === "}") {
508
- depth--;
509
- if (depth === 0 && priceStart !== -1) {
510
- const priceRaw = priceArrayContent.substring(priceStart, i + 1);
511
- const price = parsePriceObject(priceRaw);
512
- prices.push({ price, raw: priceRaw, localStart: priceStart });
513
- priceStart = -1;
514
- }
515
- }
490
+ function reorderWithIdFirst(obj) {
491
+ // Reorder object so 'id' is the first property if it exists
492
+ if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
493
+ return obj;
516
494
  }
517
495
 
518
- return prices;
496
+ const { id, ...rest } = obj;
497
+ if (id !== undefined) {
498
+ return { id, ...rest };
499
+ }
500
+ return obj;
519
501
  }
520
502
 
521
- function parsePriceObject(priceContent) {
522
- const price = {};
503
+ function toTsObjectLiteral(value, indent = 0) {
504
+ const spaces = " ".repeat(indent);
505
+ const childSpaces = " ".repeat(indent + 1);
523
506
 
524
- // Extract id if present (price id)
525
- const idMatch = priceContent.match(/id\s*:\s*["']([^"']+)["']/);
526
- if (idMatch) price.id = idMatch[1];
507
+ if (value === null || value === undefined) {
508
+ return String(value);
509
+ }
510
+
511
+ if (typeof value === "string") {
512
+ return `"${value}"`;
513
+ }
527
514
 
528
- // Extract amount
529
- const amountMatch = priceContent.match(/amount\s*:\s*(\d+)/);
530
- if (amountMatch) price.amount = parseInt(amountMatch[1], 10);
515
+ if (typeof value === "number" || typeof value === "boolean") {
516
+ return String(value);
517
+ }
531
518
 
532
- // Extract currency
533
- const currencyMatch = priceContent.match(/currency\s*:\s*["']([^"']+)["']/);
534
- if (currencyMatch) price.currency = currencyMatch[1];
519
+ if (Array.isArray(value)) {
520
+ if (value.length === 0) {
521
+ return "[]";
522
+ }
523
+ const items = value.map((item) => toTsObjectLiteral(item, indent + 1));
524
+ return `[\n${childSpaces}${items.join(`,\n${childSpaces}`)},\n${spaces}]`;
525
+ }
535
526
 
536
- // Extract interval
537
- const intervalMatch = priceContent.match(/interval\s*:\s*["']([^"']+)["']/);
538
- if (intervalMatch) price.interval = intervalMatch[1];
527
+ if (typeof value === "object") {
528
+ const entries = Object.entries(value);
529
+ if (entries.length === 0) {
530
+ return "{}";
531
+ }
532
+ const props = entries.map(
533
+ ([key, val]) => `${key}: ${toTsObjectLiteral(val, indent + 1)}`
534
+ );
535
+ return `{\n${childSpaces}${props.join(`,\n${childSpaces}`)},\n${spaces}}`;
536
+ }
539
537
 
540
- return price;
538
+ return String(value);
541
539
  }
542
540
 
543
- async function push() {
541
+ function formatConfigToTs(config) {
542
+ // Reorder plans and prices so 'id' is always first
543
+ const reorderedConfig = {};
544
+
545
+ for (const mode of ["test", "production"]) {
546
+ if (config[mode]) {
547
+ reorderedConfig[mode] = {
548
+ plans: (config[mode].plans || []).map((plan) => {
549
+ const reorderedPlan = reorderWithIdFirst(plan);
550
+ if (reorderedPlan.price) {
551
+ reorderedPlan.price = reorderedPlan.price.map(reorderWithIdFirst);
552
+ }
553
+ return reorderedPlan;
554
+ }),
555
+ };
556
+ }
557
+ }
558
+
559
+ // Convert to TypeScript object literal format (unquoted keys)
560
+ return toTsObjectLiteral(reorderedConfig, 0);
561
+ }
562
+
563
+ async function sync() {
544
564
  const billingConfigPath = path.join(process.cwd(), "billing.config.ts");
545
565
 
546
566
  if (!fs.existsSync(billingConfigPath)) {
@@ -572,28 +592,176 @@ async function push() {
572
592
  process.exit(1);
573
593
  }
574
594
 
595
+ // Determine mode based on Stripe key
596
+ let mode;
597
+ try {
598
+ mode = getMode(stripeSecretKey);
599
+ } catch (e) {
600
+ console.error("❌", e.message);
601
+ process.exit(1);
602
+ }
603
+
575
604
  const stripe = new Stripe(stripeSecretKey);
576
605
 
577
- console.log("\n📤 Pushing billing plans to Stripe...\n");
606
+ console.log(`\n🔄 Syncing billing plans with Stripe (${mode} mode)...\n`);
578
607
 
579
608
  let content = fs.readFileSync(billingConfigPath, "utf8");
580
- const parsedPlans = parseBillingConfig(content);
609
+ const { config, plans, extracted } = parseBillingConfig(content, mode);
581
610
 
582
- if (parsedPlans.length === 0) {
583
- console.log("No plans found in billing.config.ts");
584
- console.log("Add plans to the config file and run this command again.");
585
- process.exit(0);
611
+ if (!config) {
612
+ console.error(" Failed to parse billing.config.ts");
613
+ process.exit(1);
614
+ }
615
+
616
+ // Ensure the mode config exists with plans array
617
+ if (!config[mode]) {
618
+ config[mode] = { plans: [] };
619
+ }
620
+ if (!config[mode].plans) {
621
+ config[mode].plans = [];
586
622
  }
587
623
 
588
- let updatedContent = content;
624
+ let configModified = false;
625
+ let productsPulled = 0;
626
+ let pricesPulled = 0;
589
627
  let productsCreated = 0;
590
628
  let pricesCreated = 0;
591
629
  let skippedProducts = 0;
592
630
  let skippedPrices = 0;
593
631
 
594
- for (const { plan, raw } of parsedPlans) {
632
+ // === PULL: Fetch products and prices from Stripe and add missing ones ===
633
+ console.log("📥 Pulling products from Stripe...\n");
634
+
635
+ try {
636
+ // Fetch all active products from Stripe
637
+ const stripeProducts = await stripe.products.list({
638
+ active: true,
639
+ limit: 100,
640
+ });
641
+
642
+ // Fetch all active prices from Stripe
643
+ const stripePrices = await stripe.prices.list({ active: true, limit: 100 });
644
+
645
+ // Build a map of price by product
646
+ const pricesByProduct = {};
647
+ for (const price of stripePrices.data) {
648
+ const productId =
649
+ typeof price.product === "string" ? price.product : price.product.id;
650
+ if (!pricesByProduct[productId]) {
651
+ pricesByProduct[productId] = [];
652
+ }
653
+ pricesByProduct[productId].push(price);
654
+ }
655
+
656
+ // Get existing product IDs in config
657
+ const existingProductIds = new Set(
658
+ config[mode].plans.filter((p) => p.id).map((p) => p.id)
659
+ );
660
+
661
+ // Get existing price IDs in config
662
+ const existingPriceIds = new Set();
663
+ for (const plan of config[mode].plans) {
664
+ if (plan.price) {
665
+ for (const price of plan.price) {
666
+ if (price.id) {
667
+ existingPriceIds.add(price.id);
668
+ }
669
+ }
670
+ }
671
+ }
672
+
673
+ // Add missing products and their prices
674
+ for (const product of stripeProducts.data) {
675
+ if (existingProductIds.has(product.id)) {
676
+ // Product exists, but check if any prices are missing
677
+ const planIndex = config[mode].plans.findIndex(
678
+ (p) => p.id === product.id
679
+ );
680
+ const plan = config[mode].plans[planIndex];
681
+ const productPrices = pricesByProduct[product.id] || [];
682
+
683
+ for (const stripePrice of productPrices) {
684
+ if (!existingPriceIds.has(stripePrice.id)) {
685
+ // Add missing price to existing plan
686
+ const newPrice = {
687
+ id: stripePrice.id,
688
+ amount: stripePrice.unit_amount,
689
+ currency: stripePrice.currency,
690
+ interval: stripePrice.recurring?.interval || "one_time",
691
+ };
692
+ if (!plan.price) {
693
+ plan.price = [];
694
+ }
695
+ plan.price.push(newPrice);
696
+ existingPriceIds.add(stripePrice.id);
697
+ pricesPulled++;
698
+ configModified = true;
699
+ console.log(
700
+ ` 📥 Added price ${stripePrice.unit_amount / 100} ${
701
+ stripePrice.currency
702
+ }/${newPrice.interval} to "${product.name}"`
703
+ );
704
+ }
705
+ }
706
+ continue;
707
+ }
708
+
709
+ // Product doesn't exist in config, add it
710
+ const productPrices = pricesByProduct[product.id] || [];
711
+ const newPlan = {
712
+ id: product.id,
713
+ name: product.name,
714
+ description: product.description || undefined,
715
+ price: productPrices.map((p) => ({
716
+ id: p.id,
717
+ amount: p.unit_amount,
718
+ currency: p.currency,
719
+ interval: p.recurring?.interval || "one_time",
720
+ })),
721
+ };
722
+
723
+ // Remove undefined description
724
+ if (!newPlan.description) {
725
+ delete newPlan.description;
726
+ }
727
+
728
+ config[mode].plans.push(newPlan);
729
+ productsPulled++;
730
+ pricesPulled += productPrices.length;
731
+ configModified = true;
732
+
733
+ console.log(`📥 Added product "${product.name}" (${product.id})`);
734
+ for (const price of newPlan.price) {
735
+ console.log(
736
+ ` 📥 Added price ${price.amount / 100} ${price.currency}/${
737
+ price.interval
738
+ }`
739
+ );
740
+ }
741
+ }
742
+
743
+ if (productsPulled === 0 && pricesPulled === 0) {
744
+ console.log(" No new products or prices to pull from Stripe.\n");
745
+ } else {
746
+ console.log("");
747
+ }
748
+ } catch (error) {
749
+ console.error("❌ Failed to fetch products from Stripe:", error.message);
750
+ }
751
+
752
+ // === PUSH: Create products and prices in Stripe from config ===
753
+ console.log("📤 Pushing new plans to Stripe...\n");
754
+
755
+ // Re-get plans after potential modifications
756
+ const currentPlans = config[mode].plans || [];
757
+
758
+ if (currentPlans.length === 0) {
759
+ console.log(` No plans in billing.config.ts for ${mode} mode.\n`);
760
+ }
761
+
762
+ for (let index = 0; index < currentPlans.length; index++) {
763
+ const plan = currentPlans[index];
595
764
  let productId = plan.id;
596
- let updatedPlanRaw = raw;
597
765
 
598
766
  // Create product if needed
599
767
  if (!productId) {
@@ -608,12 +776,10 @@ async function push() {
608
776
  productId = product.id;
609
777
  console.log(`✅ Created product "${plan.name}" (${productId})`);
610
778
 
611
- // Add product id to plan
612
- updatedPlanRaw = updatedPlanRaw.replace(
613
- /\{/,
614
- `{\n id: "${productId}",`
615
- );
779
+ // Update the config object with the new product id
780
+ config[mode].plans[index].id = productId;
616
781
  productsCreated++;
782
+ configModified = true;
617
783
  } catch (error) {
618
784
  console.error(
619
785
  `❌ Failed to create product "${plan.name}":`,
@@ -622,17 +788,15 @@ async function push() {
622
788
  continue;
623
789
  }
624
790
  } else {
625
- console.log(`⏭️ Product "${plan.name}" already exists (${productId})`);
626
791
  skippedProducts++;
627
792
  }
628
793
 
629
794
  // Create prices if needed
630
- if (plan.prices && plan.prices.length > 0) {
631
- for (const { price, raw: priceRaw } of plan.prices) {
795
+ if (plan.price && plan.price.length > 0) {
796
+ for (let priceIndex = 0; priceIndex < plan.price.length; priceIndex++) {
797
+ const price = plan.price[priceIndex];
798
+
632
799
  if (price.id) {
633
- console.log(
634
- ` ⏭️ Price ${price.interval}/${price.currency} already exists (${price.id})`
635
- );
636
800
  skippedPrices++;
637
801
  continue;
638
802
  }
@@ -644,24 +808,27 @@ async function push() {
644
808
  }...`
645
809
  );
646
810
 
647
- const stripePrice = await stripe.prices.create({
811
+ const priceParams = {
648
812
  product: productId,
649
813
  unit_amount: price.amount,
650
814
  currency: price.currency.toLowerCase(),
651
- recurring: {
815
+ };
816
+
817
+ // Only add recurring for non-one_time intervals
818
+ if (price.interval && price.interval !== "one_time") {
819
+ priceParams.recurring = {
652
820
  interval: price.interval,
653
- },
654
- });
821
+ };
822
+ }
823
+
824
+ const stripePrice = await stripe.prices.create(priceParams);
655
825
 
656
826
  console.log(` ✅ Created price (${stripePrice.id})`);
657
827
 
658
- // Add price id to price object
659
- const updatedPriceRaw = priceRaw.replace(
660
- /\{/,
661
- `{\n id: "${stripePrice.id}",`
662
- );
663
- updatedPlanRaw = updatedPlanRaw.replace(priceRaw, updatedPriceRaw);
828
+ // Update the config object with the new price id
829
+ config[mode].plans[index].price[priceIndex].id = stripePrice.id;
664
830
  pricesCreated++;
831
+ configModified = true;
665
832
  } catch (error) {
666
833
  console.error(
667
834
  ` ❌ Failed to create price ${price.interval}/${price.currency}:`,
@@ -670,26 +837,30 @@ async function push() {
670
837
  }
671
838
  }
672
839
  }
840
+ }
673
841
 
674
- // Update content with modified plan
675
- if (updatedPlanRaw !== raw) {
676
- updatedContent = updatedContent.replace(raw, updatedPlanRaw);
677
- }
842
+ if (productsCreated === 0 && pricesCreated === 0) {
843
+ console.log(" No new products or prices to push to Stripe.\n");
678
844
  }
679
845
 
680
- // Write updated content back to file
681
- if (productsCreated > 0 || pricesCreated > 0) {
682
- fs.writeFileSync(billingConfigPath, updatedContent);
683
- console.log(
684
- `\n📝 Updated billing.config.ts with ${productsCreated} product(s) and ${pricesCreated} price(s)`
685
- );
846
+ // Write updated config back to file
847
+ if (configModified) {
848
+ const newConfigJson = formatConfigToTs(config);
849
+ const newContent =
850
+ content.substring(0, extracted.start) +
851
+ newConfigJson +
852
+ content.substring(extracted.end);
853
+ fs.writeFileSync(billingConfigPath, newContent);
854
+ console.log(`\n📝 Updated billing.config.ts`);
686
855
  }
687
856
 
688
857
  console.log(`\n✅ Done!`);
689
858
  console.log(
690
- ` Products: ${productsCreated} created, ${skippedProducts} skipped`
859
+ ` Pulled from Stripe: ${productsPulled} product(s), ${pricesPulled} price(s)`
860
+ );
861
+ console.log(
862
+ ` Pushed to Stripe: ${productsCreated} product(s), ${pricesCreated} price(s)`
691
863
  );
692
- console.log(` Prices: ${pricesCreated} created, ${skippedPrices} skipped`);
693
864
  }
694
865
 
695
866
  async function main() {
@@ -702,8 +873,8 @@ async function main() {
702
873
  await config();
703
874
  break;
704
875
 
705
- case "push":
706
- await push();
876
+ case "sync":
877
+ await sync();
707
878
  break;
708
879
 
709
880
  default:
@@ -0,0 +1,23 @@
1
+ type PriceInterval = "month" | "year" | "week" | "one_time";
2
+ type Price = {
3
+ id?: string;
4
+ amount: number;
5
+ currency: string;
6
+ interval: PriceInterval;
7
+ };
8
+ type Plan = {
9
+ id?: string;
10
+ name: string;
11
+ description?: string;
12
+ price: Price[];
13
+ };
14
+ type BillingConfig = {
15
+ test?: {
16
+ plans?: Plan[];
17
+ };
18
+ production?: {
19
+ plans?: Plan[];
20
+ };
21
+ };
22
+
23
+ export type { BillingConfig as B, PriceInterval as P, Price as a, Plan as b };
@@ -0,0 +1,23 @@
1
+ type PriceInterval = "month" | "year" | "week" | "one_time";
2
+ type Price = {
3
+ id?: string;
4
+ amount: number;
5
+ currency: string;
6
+ interval: PriceInterval;
7
+ };
8
+ type Plan = {
9
+ id?: string;
10
+ name: string;
11
+ description?: string;
12
+ price: Price[];
13
+ };
14
+ type BillingConfig = {
15
+ test?: {
16
+ plans?: Plan[];
17
+ };
18
+ production?: {
19
+ plans?: Plan[];
20
+ };
21
+ };
22
+
23
+ export type { BillingConfig as B, PriceInterval as P, Price as a, Plan as b };
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { P as PriceInterval } from './BillingConfig-BYrAQ7Wx.mjs';
1
+ import { P as PriceInterval } from './BillingConfig-n6VbfqGY.mjs';
2
2
 
3
3
  interface CheckoutOptions {
4
4
  /**
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { P as PriceInterval } from './BillingConfig-BYrAQ7Wx.js';
1
+ import { P as PriceInterval } from './BillingConfig-n6VbfqGY.js';
2
2
 
3
3
  interface CheckoutOptions {
4
4
  /**
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import Stripe from 'stripe';
2
- import { B as BillingConfig, P as PriceInterval } from './BillingConfig-BYrAQ7Wx.mjs';
3
- export { b as Plan, a as Price } from './BillingConfig-BYrAQ7Wx.mjs';
2
+ import { B as BillingConfig, P as PriceInterval } from './BillingConfig-n6VbfqGY.mjs';
3
+ export { b as Plan, a as Price } from './BillingConfig-n6VbfqGY.mjs';
4
4
 
5
5
  interface StripeWebhookCallbacks {
6
6
  /**
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import Stripe from 'stripe';
2
- import { B as BillingConfig, P as PriceInterval } from './BillingConfig-BYrAQ7Wx.js';
3
- export { b as Plan, a as Price } from './BillingConfig-BYrAQ7Wx.js';
2
+ import { B as BillingConfig, P as PriceInterval } from './BillingConfig-n6VbfqGY.js';
3
+ export { b as Plan, a as Price } from './BillingConfig-n6VbfqGY.js';
4
4
 
5
5
  interface StripeWebhookCallbacks {
6
6
  /**
package/dist/index.js CHANGED
@@ -37,6 +37,19 @@ module.exports = __toCommonJS(index_exports);
37
37
  // src/handler.ts
38
38
  var import_stripe_sync_engine = require("@supabase/stripe-sync-engine");
39
39
  var import_stripe = __toESM(require("stripe"));
40
+
41
+ // src/utils.ts
42
+ var getMode = (stripeKey) => {
43
+ if (stripeKey.includes("_test_")) {
44
+ return "test";
45
+ } else if (stripeKey.includes("_live_")) {
46
+ return "production";
47
+ } else {
48
+ throw new Error("Invalid Stripe key");
49
+ }
50
+ };
51
+
52
+ // src/handler.ts
40
53
  function createStripeHandler(config = {}) {
41
54
  const {
42
55
  stripeSecretKey = process.env.STRIPE_SECRET_KEY,
@@ -58,19 +71,19 @@ function createStripeHandler(config = {}) {
58
71
  stripeSecretKey,
59
72
  stripeWebhookSecret
60
73
  }) : null;
61
- function resolvePriceId(body) {
74
+ function resolvePriceId(body, mode) {
62
75
  if (body.priceId) {
63
76
  return body.priceId;
64
77
  }
65
78
  if (!body.interval) {
66
79
  throw new Error("interval is required when using planName or planId");
67
80
  }
68
- if (!billingConfig?.plans) {
81
+ if (!billingConfig?.[mode]?.plans) {
69
82
  throw new Error(
70
83
  "billingConfig with plans is required when using planName or planId"
71
84
  );
72
85
  }
73
- const plan = body.planName ? billingConfig.plans.find((p) => p.name === body.planName) : body.planId ? billingConfig.plans.find((p) => p.id === body.planId) : null;
86
+ const plan = body.planName ? billingConfig[mode]?.plans?.find((p) => p.name === body.planName) : body.planId ? billingConfig[mode]?.plans?.find((p) => p.id === body.planId) : null;
74
87
  if (!plan) {
75
88
  const identifier = body.planName || body.planId;
76
89
  throw new Error(`Plan not found: ${identifier}`);
@@ -106,7 +119,7 @@ function createStripeHandler(config = {}) {
106
119
  const origin = request.headers.get("origin") || "";
107
120
  const successUrl = body.successUrl || defaultSuccessUrl || `${origin}/success?session_id={CHECKOUT_SESSION_ID}`;
108
121
  const cancelUrl = body.cancelUrl || defaultCancelUrl || `${origin}/`;
109
- const priceId = resolvePriceId(body);
122
+ const priceId = resolvePriceId(body, getMode(stripeSecretKey));
110
123
  const mode = await getPriceMode(priceId);
111
124
  const sessionParams = {
112
125
  line_items: [
package/dist/index.mjs CHANGED
@@ -1,6 +1,19 @@
1
1
  // src/handler.ts
2
2
  import { StripeSync } from "@supabase/stripe-sync-engine";
3
3
  import Stripe from "stripe";
4
+
5
+ // src/utils.ts
6
+ var getMode = (stripeKey) => {
7
+ if (stripeKey.includes("_test_")) {
8
+ return "test";
9
+ } else if (stripeKey.includes("_live_")) {
10
+ return "production";
11
+ } else {
12
+ throw new Error("Invalid Stripe key");
13
+ }
14
+ };
15
+
16
+ // src/handler.ts
4
17
  function createStripeHandler(config = {}) {
5
18
  const {
6
19
  stripeSecretKey = process.env.STRIPE_SECRET_KEY,
@@ -22,19 +35,19 @@ function createStripeHandler(config = {}) {
22
35
  stripeSecretKey,
23
36
  stripeWebhookSecret
24
37
  }) : null;
25
- function resolvePriceId(body) {
38
+ function resolvePriceId(body, mode) {
26
39
  if (body.priceId) {
27
40
  return body.priceId;
28
41
  }
29
42
  if (!body.interval) {
30
43
  throw new Error("interval is required when using planName or planId");
31
44
  }
32
- if (!billingConfig?.plans) {
45
+ if (!billingConfig?.[mode]?.plans) {
33
46
  throw new Error(
34
47
  "billingConfig with plans is required when using planName or planId"
35
48
  );
36
49
  }
37
- const plan = body.planName ? billingConfig.plans.find((p) => p.name === body.planName) : body.planId ? billingConfig.plans.find((p) => p.id === body.planId) : null;
50
+ const plan = body.planName ? billingConfig[mode]?.plans?.find((p) => p.name === body.planName) : body.planId ? billingConfig[mode]?.plans?.find((p) => p.id === body.planId) : null;
38
51
  if (!plan) {
39
52
  const identifier = body.planName || body.planId;
40
53
  throw new Error(`Plan not found: ${identifier}`);
@@ -70,7 +83,7 @@ function createStripeHandler(config = {}) {
70
83
  const origin = request.headers.get("origin") || "";
71
84
  const successUrl = body.successUrl || defaultSuccessUrl || `${origin}/success?session_id={CHECKOUT_SESSION_ID}`;
72
85
  const cancelUrl = body.cancelUrl || defaultCancelUrl || `${origin}/`;
73
- const priceId = resolvePriceId(body);
86
+ const priceId = resolvePriceId(body, getMode(stripeSecretKey));
74
87
  const mode = await getPriceMode(priceId);
75
88
  const sessionParams = {
76
89
  line_items: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stripe-no-webhooks",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "author": "Ramon Garate",
5
5
  "description": "Stripe integration without dealing with webhooks",
6
6
  "main": "./dist/index.js",
@@ -1,26 +1,29 @@
1
1
  import type { BillingConfig } from "stripe-no-webhooks";
2
2
 
3
3
  const billingConfig: BillingConfig = {
4
- /*
4
+ test: {
5
5
  plans: [
6
- {
7
- name: "Premium",
8
- description: "Access to all features",
9
- price: [
10
- {
11
- amount: 1000, // in cents, 1000 = $10.00
12
- currency: "usd",
13
- interval: "month",
14
- },
15
- {
16
- amount: 10000, // in cents, 10000 = $100.00
17
- currency: "usd",
18
- interval: "year",
19
- },
20
- ],
21
- },
6
+ // {
7
+ // name: "Premium",
8
+ // description: "Access to all features",
9
+ // price: [
10
+ // {
11
+ // amount: 1000, // in cents, 1000 = $10.00
12
+ // currency: "usd",
13
+ // interval: "month",
14
+ // },
15
+ // {
16
+ // amount: 10000, // in cents, 10000 = $100.00
17
+ // currency: "usd",
18
+ // interval: "year",
19
+ // },
20
+ // ],
21
+ // },
22
22
  ],
23
- */
23
+ },
24
+ production: {
25
+ plans: [],
26
+ },
24
27
  };
25
28
 
26
29
  export default billingConfig;