spaps 0.4.1 → 0.4.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/local-server.js +172 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spaps",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Sweet Potato Authentication & Payment Service CLI - Zero-config local development and project scaffolding",
5
5
  "main": "bin/spaps.js",
6
6
  "bin": {
@@ -37,7 +37,7 @@ class LocalServer {
37
37
  origin: true,
38
38
  credentials: true,
39
39
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
40
- allowedHeaders: ['Content-Type', 'Authorization', 'X-API-Key', 'X-Test-User', 'x-local-mode'],
40
+ allowedHeaders: ['Content-Type', 'Authorization', 'X-API-Key', 'X-Test-User', 'x-local-mode', 'X-Local-Mode'],
41
41
  }));
42
42
 
43
43
  // Body parsing
@@ -608,10 +608,10 @@ class LocalServer {
608
608
  }
609
609
  });
610
610
 
611
- // POST /api/stripe/products - Create new product
611
+ // POST /api/stripe/products - Create new product with optional price
612
612
  this.app.post('/api/stripe/products', async (req, res) => {
613
613
  try {
614
- const { name, description, images, metadata = {}, active = true } = req.body;
614
+ const { name, description, images, metadata = {}, active = true, price, currency = 'usd' } = req.body;
615
615
 
616
616
  if (!name) {
617
617
  return res.status(400).json({
@@ -634,29 +634,67 @@ class LocalServer {
634
634
  }
635
635
  });
636
636
 
637
+ let stripePrice = null;
638
+
639
+ // If price is provided, create a price for the product
640
+ if (price !== undefined && price !== null && price !== '') {
641
+ stripePrice = await stripe.prices.create({
642
+ product: stripeProduct.id,
643
+ unit_amount: parseInt(price), // Price in cents
644
+ currency: currency,
645
+ metadata: {
646
+ spaps_managed: 'true',
647
+ created_by: 'spaps_cli'
648
+ }
649
+ });
650
+
651
+ // Update product with default price
652
+ await stripe.products.update(stripeProduct.id, {
653
+ default_price: stripePrice.id
654
+ });
655
+ }
656
+
657
+ // Fetch the updated product with default_price
658
+ const updatedProduct = await stripe.products.retrieve(stripeProduct.id, {
659
+ expand: ['default_price']
660
+ });
661
+
637
662
  res.json({
638
663
  success: true,
639
664
  data: {
640
665
  product: {
641
- id: stripeProduct.id,
642
- name: stripeProduct.name,
643
- description: stripeProduct.description,
644
- images: stripeProduct.images,
645
- active: stripeProduct.active,
646
- metadata: stripeProduct.metadata,
647
- created: stripeProduct.created
666
+ id: updatedProduct.id,
667
+ name: updatedProduct.name,
668
+ description: updatedProduct.description,
669
+ images: updatedProduct.images,
670
+ active: updatedProduct.active,
671
+ metadata: updatedProduct.metadata,
672
+ created: updatedProduct.created,
673
+ default_price: updatedProduct.default_price ? {
674
+ id: updatedProduct.default_price.id,
675
+ unit_amount: updatedProduct.default_price.unit_amount,
676
+ currency: updatedProduct.default_price.currency
677
+ } : null
648
678
  }
649
679
  }
650
680
  });
651
681
  } else {
652
682
  // Create locally
683
+ const productPrice = price ? parseInt(price) : 0;
653
684
  const product = this.adminManager.createProduct({
654
685
  name,
655
686
  description,
656
- price: 0, // Will need to set price separately
657
- currency: 'usd'
687
+ price: productPrice,
688
+ currency: currency
658
689
  });
659
690
 
691
+ // Add mock default_price structure for consistency
692
+ product.default_price = productPrice > 0 ? {
693
+ id: `price_${product.id}`,
694
+ unit_amount: productPrice,
695
+ currency: currency
696
+ } : null;
697
+
660
698
  res.json({
661
699
  success: true,
662
700
  data: { product }
@@ -730,6 +768,128 @@ class LocalServer {
730
768
  }
731
769
  });
732
770
 
771
+ // POST /api/stripe/prices - Create a new price for a product
772
+ this.app.post('/api/stripe/prices', async (req, res) => {
773
+ try {
774
+ const { product_id, unit_amount, currency = 'usd', recurring, metadata = {} } = req.body;
775
+
776
+ if (!product_id || !unit_amount) {
777
+ return res.status(400).json({
778
+ success: false,
779
+ error: { message: 'Product ID and unit amount are required' }
780
+ });
781
+ }
782
+
783
+ if (USE_REAL_STRIPE) {
784
+ const priceData = {
785
+ product: product_id,
786
+ unit_amount: parseInt(unit_amount),
787
+ currency,
788
+ metadata: {
789
+ ...metadata,
790
+ spaps_managed: 'true'
791
+ }
792
+ };
793
+
794
+ // Add recurring if specified
795
+ if (recurring) {
796
+ priceData.recurring = recurring;
797
+ }
798
+
799
+ const stripePrice = await stripe.prices.create(priceData);
800
+
801
+ res.json({
802
+ success: true,
803
+ data: {
804
+ price: {
805
+ id: stripePrice.id,
806
+ product: stripePrice.product,
807
+ unit_amount: stripePrice.unit_amount,
808
+ currency: stripePrice.currency,
809
+ recurring: stripePrice.recurring,
810
+ metadata: stripePrice.metadata
811
+ }
812
+ }
813
+ });
814
+ } else {
815
+ // Mock price creation
816
+ const price = {
817
+ id: `price_${Date.now()}`,
818
+ product: product_id,
819
+ unit_amount: parseInt(unit_amount),
820
+ currency,
821
+ recurring,
822
+ metadata
823
+ };
824
+
825
+ res.json({
826
+ success: true,
827
+ data: { price }
828
+ });
829
+ }
830
+ } catch (error) {
831
+ console.error('Create price error:', error);
832
+ res.status(500).json({
833
+ success: false,
834
+ error: {
835
+ code: 'CREATE_PRICE_ERROR',
836
+ message: error.message || 'Failed to create price'
837
+ }
838
+ });
839
+ }
840
+ });
841
+
842
+ // PUT /api/stripe/products/:productId/default-price - Update product's default price
843
+ this.app.put('/api/stripe/products/:productId/default-price', async (req, res) => {
844
+ try {
845
+ const { productId } = req.params;
846
+ const { price_id } = req.body;
847
+
848
+ if (!price_id) {
849
+ return res.status(400).json({
850
+ success: false,
851
+ error: { message: 'Price ID is required' }
852
+ });
853
+ }
854
+
855
+ if (USE_REAL_STRIPE) {
856
+ const stripeProduct = await stripe.products.update(productId, {
857
+ default_price: price_id
858
+ });
859
+
860
+ res.json({
861
+ success: true,
862
+ data: {
863
+ product: {
864
+ id: stripeProduct.id,
865
+ name: stripeProduct.name,
866
+ default_price: stripeProduct.default_price
867
+ }
868
+ }
869
+ });
870
+ } else {
871
+ res.json({
872
+ success: true,
873
+ data: {
874
+ product: {
875
+ id: productId,
876
+ default_price: price_id
877
+ }
878
+ }
879
+ });
880
+ }
881
+ } catch (error) {
882
+ console.error('Update default price error:', error);
883
+ res.status(500).json({
884
+ success: false,
885
+ error: {
886
+ code: 'UPDATE_DEFAULT_PRICE_ERROR',
887
+ message: error.message || 'Failed to update default price'
888
+ }
889
+ });
890
+ }
891
+ });
892
+
733
893
  // DELETE /api/stripe/products/:productId - Archive product
734
894
  this.app.delete('/api/stripe/products/:productId', async (req, res) => {
735
895
  try {