spaps 0.3.6 → 0.3.8
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 +114 -59
package/package.json
CHANGED
package/src/local-server.js
CHANGED
|
@@ -249,27 +249,33 @@ class LocalServer {
|
|
|
249
249
|
limit: req.query.limit ? parseInt(req.query.limit) : 10
|
|
250
250
|
});
|
|
251
251
|
|
|
252
|
-
// Get prices for each product
|
|
252
|
+
// Get prices for each product and filter out local-only products
|
|
253
253
|
const productsWithPrices = await Promise.all(
|
|
254
|
-
products.data
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
254
|
+
products.data
|
|
255
|
+
.filter(product => {
|
|
256
|
+
// Only show products that were synced from SPAPS (have spaps_managed metadata)
|
|
257
|
+
// or don't start with prod_local_ (which are local-only placeholders)
|
|
258
|
+
return product.metadata?.spaps_managed === 'true' || !product.id.startsWith('prod_local_');
|
|
259
|
+
})
|
|
260
|
+
.map(async (product) => {
|
|
261
|
+
const prices = await stripe.prices.list({
|
|
262
|
+
product: product.id,
|
|
263
|
+
active: true,
|
|
264
|
+
limit: 1
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
const defaultPrice = prices.data[0];
|
|
268
|
+
return {
|
|
269
|
+
id: product.id,
|
|
270
|
+
name: product.name,
|
|
271
|
+
description: product.description,
|
|
272
|
+
price: defaultPrice ? defaultPrice.unit_amount : 0,
|
|
273
|
+
currency: defaultPrice ? defaultPrice.currency : 'usd',
|
|
274
|
+
price_id: defaultPrice ? defaultPrice.id : null,
|
|
275
|
+
active: product.active,
|
|
276
|
+
metadata: product.metadata
|
|
277
|
+
};
|
|
278
|
+
})
|
|
273
279
|
);
|
|
274
280
|
|
|
275
281
|
res.json({
|
|
@@ -349,6 +355,54 @@ class LocalServer {
|
|
|
349
355
|
});
|
|
350
356
|
});
|
|
351
357
|
|
|
358
|
+
// Admin whitelist check endpoint
|
|
359
|
+
this.app.post('/api/v1/admin/whitelist/check', (req, res) => {
|
|
360
|
+
const { email } = req.body;
|
|
361
|
+
|
|
362
|
+
if (!email) {
|
|
363
|
+
return res.status(400).json({
|
|
364
|
+
success: false,
|
|
365
|
+
error: { message: 'Email is required' }
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Mock whitelist check - some emails are "whitelisted"
|
|
370
|
+
const whitelistedEmails = ['vip@example.com', 'admin@example.com', 'premium@example.com'];
|
|
371
|
+
const isWhitelisted = whitelistedEmails.includes(email.toLowerCase());
|
|
372
|
+
|
|
373
|
+
res.json({
|
|
374
|
+
success: true,
|
|
375
|
+
data: {
|
|
376
|
+
email,
|
|
377
|
+
whitelisted: isWhitelisted,
|
|
378
|
+
reason: isWhitelisted ? 'VIP access granted' : 'Standard access only'
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// Admin pricing update endpoint
|
|
384
|
+
this.app.post('/api/v1/admin/pricing/update', (req, res) => {
|
|
385
|
+
const { product_id, new_price, currency = 'usd' } = req.body;
|
|
386
|
+
|
|
387
|
+
if (!product_id || !new_price) {
|
|
388
|
+
return res.status(400).json({
|
|
389
|
+
success: false,
|
|
390
|
+
error: { message: 'Product ID and new price are required' }
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
res.json({
|
|
395
|
+
success: true,
|
|
396
|
+
data: {
|
|
397
|
+
product_id,
|
|
398
|
+
old_price: 999,
|
|
399
|
+
new_price,
|
|
400
|
+
currency,
|
|
401
|
+
updated_at: new Date().toISOString()
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
|
|
352
406
|
// Admin product sync endpoint - REAL or MOCK based on config
|
|
353
407
|
this.app.post('/api/v1/admin/products/sync', async (req, res) => {
|
|
354
408
|
try {
|
|
@@ -359,51 +413,52 @@ class LocalServer {
|
|
|
359
413
|
|
|
360
414
|
for (const product of localProducts) {
|
|
361
415
|
try {
|
|
362
|
-
// Check if product already exists in Stripe
|
|
416
|
+
// Check if product already exists in Stripe by searching metadata
|
|
363
417
|
let stripeProduct;
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
description: product.description,
|
|
373
|
-
metadata: {
|
|
374
|
-
spaps_managed: 'true',
|
|
375
|
-
created_by: 'spaps_admin'
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
// Create corresponding price
|
|
380
|
-
await stripe.prices.create({
|
|
381
|
-
id: product.price_id,
|
|
382
|
-
product: stripeProduct.id,
|
|
383
|
-
unit_amount: product.price,
|
|
384
|
-
currency: product.currency,
|
|
385
|
-
metadata: {
|
|
386
|
-
spaps_managed: 'true'
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
syncResults.push({
|
|
391
|
-
id: product.id,
|
|
392
|
-
name: product.name,
|
|
393
|
-
action: 'created',
|
|
394
|
-
stripe_id: stripeProduct.id
|
|
395
|
-
});
|
|
396
|
-
} else {
|
|
397
|
-
throw error;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
418
|
+
const existingProducts = await stripe.products.list({
|
|
419
|
+
limit: 100,
|
|
420
|
+
expand: ['data.default_price']
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
stripeProduct = existingProducts.data.find(p =>
|
|
424
|
+
p.metadata && p.metadata.spaps_id === product.id
|
|
425
|
+
);
|
|
400
426
|
|
|
401
|
-
if (stripeProduct
|
|
427
|
+
if (!stripeProduct) {
|
|
428
|
+
// Create new product in Stripe
|
|
429
|
+
stripeProduct = await stripe.products.create({
|
|
430
|
+
name: product.name,
|
|
431
|
+
description: product.description,
|
|
432
|
+
metadata: {
|
|
433
|
+
spaps_managed: 'true',
|
|
434
|
+
created_by: 'spaps_admin',
|
|
435
|
+
spaps_id: product.id
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
// Create corresponding price
|
|
440
|
+
await stripe.prices.create({
|
|
441
|
+
product: stripeProduct.id,
|
|
442
|
+
unit_amount: product.price,
|
|
443
|
+
currency: product.currency,
|
|
444
|
+
metadata: {
|
|
445
|
+
spaps_managed: 'true',
|
|
446
|
+
spaps_price_id: product.price_id
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
syncResults.push({
|
|
451
|
+
id: product.id,
|
|
452
|
+
name: product.name,
|
|
453
|
+
action: 'created',
|
|
454
|
+
stripe_id: stripeProduct.id
|
|
455
|
+
});
|
|
456
|
+
} else {
|
|
402
457
|
// Update existing product
|
|
403
458
|
await stripe.products.update(stripeProduct.id, {
|
|
404
459
|
name: product.name,
|
|
405
460
|
description: product.description,
|
|
406
|
-
active: product.active
|
|
461
|
+
active: product.active !== false
|
|
407
462
|
});
|
|
408
463
|
|
|
409
464
|
syncResults.push({
|