spaps 0.3.10 → 0.4.1
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/package.json +1 -1
- package/src/local-server.js +235 -0
package/package.json
CHANGED
package/src/local-server.js
CHANGED
|
@@ -539,6 +539,241 @@ class LocalServer {
|
|
|
539
539
|
}
|
|
540
540
|
|
|
541
541
|
setupStripeRoutes() {
|
|
542
|
+
// Enhanced Stripe Product Management - Full CRUD
|
|
543
|
+
|
|
544
|
+
// GET /api/stripe/products - List all products with filtering
|
|
545
|
+
this.app.get('/api/stripe/products', async (req, res) => {
|
|
546
|
+
try {
|
|
547
|
+
if (USE_REAL_STRIPE) {
|
|
548
|
+
const { active, category, limit = '100' } = req.query;
|
|
549
|
+
|
|
550
|
+
const products = await stripe.products.list({
|
|
551
|
+
active: active === 'true' ? true : active === 'false' ? false : undefined,
|
|
552
|
+
limit: parseInt(limit),
|
|
553
|
+
expand: ['data.default_price']
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
// Filter out non-SPAPS managed products if needed
|
|
557
|
+
let filteredProducts = products.data;
|
|
558
|
+
if (category === 'spaps') {
|
|
559
|
+
filteredProducts = products.data.filter(p =>
|
|
560
|
+
p.metadata && p.metadata.spaps_managed === 'true'
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
res.json({
|
|
565
|
+
success: true,
|
|
566
|
+
data: {
|
|
567
|
+
products: filteredProducts.map(product => ({
|
|
568
|
+
id: product.id,
|
|
569
|
+
name: product.name,
|
|
570
|
+
description: product.description,
|
|
571
|
+
images: product.images,
|
|
572
|
+
active: product.active,
|
|
573
|
+
metadata: product.metadata,
|
|
574
|
+
default_price: product.default_price ? {
|
|
575
|
+
id: product.default_price.id,
|
|
576
|
+
unit_amount: product.default_price.unit_amount,
|
|
577
|
+
currency: product.default_price.currency,
|
|
578
|
+
recurring: product.default_price.recurring
|
|
579
|
+
} : null,
|
|
580
|
+
created: product.created,
|
|
581
|
+
updated: product.updated
|
|
582
|
+
})),
|
|
583
|
+
has_more: products.has_more,
|
|
584
|
+
total_count: filteredProducts.length
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
} else {
|
|
588
|
+
// Mock response
|
|
589
|
+
const localProducts = this.adminManager.listProducts();
|
|
590
|
+
res.json({
|
|
591
|
+
success: true,
|
|
592
|
+
data: {
|
|
593
|
+
products: localProducts,
|
|
594
|
+
has_more: false,
|
|
595
|
+
total_count: localProducts.length
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
} catch (error) {
|
|
600
|
+
console.error('List products error:', error);
|
|
601
|
+
res.status(500).json({
|
|
602
|
+
success: false,
|
|
603
|
+
error: {
|
|
604
|
+
code: 'LIST_PRODUCTS_ERROR',
|
|
605
|
+
message: error.message || 'Failed to list products'
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
// POST /api/stripe/products - Create new product
|
|
612
|
+
this.app.post('/api/stripe/products', async (req, res) => {
|
|
613
|
+
try {
|
|
614
|
+
const { name, description, images, metadata = {}, active = true } = req.body;
|
|
615
|
+
|
|
616
|
+
if (!name) {
|
|
617
|
+
return res.status(400).json({
|
|
618
|
+
success: false,
|
|
619
|
+
error: { message: 'Product name is required' }
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (USE_REAL_STRIPE) {
|
|
624
|
+
// Create product in Stripe
|
|
625
|
+
const stripeProduct = await stripe.products.create({
|
|
626
|
+
name,
|
|
627
|
+
description,
|
|
628
|
+
images,
|
|
629
|
+
active,
|
|
630
|
+
metadata: {
|
|
631
|
+
...metadata,
|
|
632
|
+
spaps_managed: 'true',
|
|
633
|
+
created_by: 'spaps_cli'
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
res.json({
|
|
638
|
+
success: true,
|
|
639
|
+
data: {
|
|
640
|
+
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
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
} else {
|
|
652
|
+
// Create locally
|
|
653
|
+
const product = this.adminManager.createProduct({
|
|
654
|
+
name,
|
|
655
|
+
description,
|
|
656
|
+
price: 0, // Will need to set price separately
|
|
657
|
+
currency: 'usd'
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
res.json({
|
|
661
|
+
success: true,
|
|
662
|
+
data: { product }
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
} catch (error) {
|
|
666
|
+
console.error('Create product error:', error);
|
|
667
|
+
res.status(500).json({
|
|
668
|
+
success: false,
|
|
669
|
+
error: {
|
|
670
|
+
code: 'CREATE_PRODUCT_ERROR',
|
|
671
|
+
message: error.message || 'Failed to create product'
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
// PUT /api/stripe/products/:productId - Update product
|
|
678
|
+
this.app.put('/api/stripe/products/:productId', async (req, res) => {
|
|
679
|
+
try {
|
|
680
|
+
const { productId } = req.params;
|
|
681
|
+
const { name, description, images, metadata, active } = req.body;
|
|
682
|
+
|
|
683
|
+
if (USE_REAL_STRIPE) {
|
|
684
|
+
// Update in Stripe
|
|
685
|
+
const updateData = {};
|
|
686
|
+
if (name !== undefined) updateData.name = name;
|
|
687
|
+
if (description !== undefined) updateData.description = description;
|
|
688
|
+
if (images !== undefined) updateData.images = images;
|
|
689
|
+
if (metadata !== undefined) updateData.metadata = metadata;
|
|
690
|
+
if (active !== undefined) updateData.active = active;
|
|
691
|
+
|
|
692
|
+
const stripeProduct = await stripe.products.update(productId, updateData);
|
|
693
|
+
|
|
694
|
+
res.json({
|
|
695
|
+
success: true,
|
|
696
|
+
data: {
|
|
697
|
+
product: {
|
|
698
|
+
id: stripeProduct.id,
|
|
699
|
+
name: stripeProduct.name,
|
|
700
|
+
description: stripeProduct.description,
|
|
701
|
+
images: stripeProduct.images,
|
|
702
|
+
active: stripeProduct.active,
|
|
703
|
+
metadata: stripeProduct.metadata,
|
|
704
|
+
updated: stripeProduct.updated
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
} else {
|
|
709
|
+
// Update locally
|
|
710
|
+
const product = this.adminManager.updateProduct(productId, {
|
|
711
|
+
name,
|
|
712
|
+
description,
|
|
713
|
+
active
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
res.json({
|
|
717
|
+
success: true,
|
|
718
|
+
data: { product }
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
} catch (error) {
|
|
722
|
+
console.error('Update product error:', error);
|
|
723
|
+
res.status(500).json({
|
|
724
|
+
success: false,
|
|
725
|
+
error: {
|
|
726
|
+
code: 'UPDATE_PRODUCT_ERROR',
|
|
727
|
+
message: error.message || 'Failed to update product'
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
// DELETE /api/stripe/products/:productId - Archive product
|
|
734
|
+
this.app.delete('/api/stripe/products/:productId', async (req, res) => {
|
|
735
|
+
try {
|
|
736
|
+
const { productId } = req.params;
|
|
737
|
+
|
|
738
|
+
if (USE_REAL_STRIPE) {
|
|
739
|
+
// Archive in Stripe (can't truly delete)
|
|
740
|
+
const stripeProduct = await stripe.products.update(productId, {
|
|
741
|
+
active: false
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
res.json({
|
|
745
|
+
success: true,
|
|
746
|
+
message: 'Product archived successfully',
|
|
747
|
+
data: {
|
|
748
|
+
product: {
|
|
749
|
+
id: stripeProduct.id,
|
|
750
|
+
active: stripeProduct.active,
|
|
751
|
+
updated: stripeProduct.updated
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
});
|
|
755
|
+
} else {
|
|
756
|
+
// Soft delete locally
|
|
757
|
+
const result = this.adminManager.deleteProduct(productId);
|
|
758
|
+
|
|
759
|
+
res.json({
|
|
760
|
+
success: true,
|
|
761
|
+
message: 'Product deleted successfully',
|
|
762
|
+
data: result
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
} catch (error) {
|
|
766
|
+
console.error('Delete product error:', error);
|
|
767
|
+
res.status(500).json({
|
|
768
|
+
success: false,
|
|
769
|
+
error: {
|
|
770
|
+
code: 'DELETE_PRODUCT_ERROR',
|
|
771
|
+
message: error.message || 'Failed to delete product'
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
|
|
542
777
|
// Mock Stripe checkout session
|
|
543
778
|
this.app.post('/api/stripe/create-checkout-session', async (req, res) => {
|
|
544
779
|
const { price_id, success_url, cancel_url } = req.body;
|