@withvlibe/base-sdk 1.0.1 → 1.1.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/README.md CHANGED
@@ -309,6 +309,290 @@ const products = await db.query<Product>('products', { where: { isActive: true }
309
309
  const orders = await db.query<Order>('orders', { where: { userId: user.id } });
310
310
  ```
311
311
 
312
+ ## E-Commerce
313
+
314
+ The SDK provides specialized e-commerce functionality through `VlibeBaseEcommerce`.
315
+
316
+ ### Setup
317
+
318
+ ```typescript
319
+ import { VlibeBaseEcommerce } from '@withvlibe/base-sdk';
320
+
321
+ // Initialize with database client
322
+ export const ecommerce = new VlibeBaseEcommerce(db);
323
+ ```
324
+
325
+ ### Products
326
+
327
+ ```typescript
328
+ // Create a product
329
+ const product = await ecommerce.createProduct({
330
+ name: 'Premium T-Shirt',
331
+ description: 'High-quality cotton t-shirt',
332
+ price: 2999, // $29.99 in cents
333
+ currency: 'usd',
334
+ stock: 100,
335
+ images: ['https://example.com/tshirt.jpg'],
336
+ category: 'apparel',
337
+ isActive: true,
338
+ });
339
+
340
+ // List products
341
+ const { products, total } = await ecommerce.listProducts({
342
+ category: 'apparel',
343
+ isActive: true,
344
+ sortBy: 'created_at',
345
+ limit: 20,
346
+ });
347
+
348
+ // Update inventory
349
+ await ecommerce.updateInventory(productId, 50, 'set');
350
+ await ecommerce.updateInventory(productId, 5, 'increment');
351
+ await ecommerce.updateInventory(productId, 3, 'decrement');
352
+
353
+ // Get low stock products
354
+ const lowStock = await ecommerce.getLowStockProducts(10); // threshold: 10
355
+ ```
356
+
357
+ ### Shopping Cart
358
+
359
+ ```typescript
360
+ // Add to cart
361
+ await ecommerce.addToCart(userId, {
362
+ productId: 'product-123',
363
+ quantity: 2,
364
+ });
365
+
366
+ // Get cart (lightweight - only IDs and quantities)
367
+ const cart = await ecommerce.getCart(userId);
368
+ // Returns: [{ productId: '...', quantity: 2 }]
369
+
370
+ // Get cart with full product details
371
+ const detailedCart = await ecommerce.getCartWithDetails(userId);
372
+ // Returns: [{ productId: '...', quantity: 2, product: {...}, lineTotal: 5998 }]
373
+
374
+ // Update quantity
375
+ await ecommerce.updateCartItem(userId, productId, 5);
376
+
377
+ // Remove item (set quantity to 0)
378
+ await ecommerce.updateCartItem(userId, productId, 0);
379
+
380
+ // Calculate order totals
381
+ const calculation = await ecommerce.calculateOrderTotal(cart);
382
+ console.log('Subtotal:', calculation.subtotal);
383
+ console.log('Tax:', calculation.tax);
384
+ console.log('Shipping:', calculation.shipping);
385
+ console.log('Total:', calculation.total);
386
+
387
+ // Checkout (creates order and clears cart)
388
+ const order = await ecommerce.checkout(userId, {
389
+ line1: '123 Main St',
390
+ city: 'San Francisco',
391
+ state: 'CA',
392
+ postalCode: '94102',
393
+ country: 'US',
394
+ }, paymentMethodId);
395
+ ```
396
+
397
+ ### Orders
398
+
399
+ ```typescript
400
+ // Create an order directly
401
+ const order = await ecommerce.createOrder({
402
+ userId: 'user-123',
403
+ items: [
404
+ { productId: 'product-1', quantity: 2 },
405
+ { productId: 'product-2', quantity: 1 },
406
+ ],
407
+ shippingAddress: {
408
+ line1: '123 Main St',
409
+ city: 'San Francisco',
410
+ state: 'CA',
411
+ postalCode: '94102',
412
+ country: 'US',
413
+ },
414
+ });
415
+
416
+ // List orders
417
+ const { orders, total } = await ecommerce.listOrders({
418
+ userId: 'user-123',
419
+ status: 'pending',
420
+ limit: 10,
421
+ });
422
+
423
+ // Update order status
424
+ await ecommerce.updateOrderStatus(orderId, 'shipped');
425
+
426
+ // Cancel order (optionally restore inventory)
427
+ await ecommerce.cancelOrder(orderId, true);
428
+ ```
429
+
430
+ ### Analytics
431
+
432
+ ```typescript
433
+ // Revenue stats
434
+ const stats = await ecommerce.getRevenueStats('month');
435
+ console.log('Revenue:', stats.totalRevenue);
436
+ console.log('Orders:', stats.totalOrders);
437
+ console.log('AOV:', stats.averageOrderValue);
438
+ console.log('Trend:', stats.trend.revenue); // % change
439
+
440
+ // Top products
441
+ const topProducts = await ecommerce.getTopProducts(10, 'week');
442
+
443
+ // Order statistics
444
+ const orderStats = await ecommerce.getOrderStats();
445
+ console.log('Pending:', orderStats.pending);
446
+ console.log('Delivered:', orderStats.delivered);
447
+ ```
448
+
449
+ ### React Hooks for E-Commerce
450
+
451
+ ```tsx
452
+ import { useProducts, useCart, useOrders } from '@withvlibe/base-sdk/react';
453
+
454
+ function ProductList() {
455
+ const { products, loading, createProduct, updateProduct } = useProducts(ecommerce, {
456
+ category: 'apparel',
457
+ isActive: true,
458
+ });
459
+
460
+ if (loading) return <div>Loading...</div>;
461
+
462
+ return (
463
+ <div>
464
+ {products.map(product => (
465
+ <div key={product.id}>
466
+ <h3>{product.name}</h3>
467
+ <p>${(product.price / 100).toFixed(2)}</p>
468
+ <p>Stock: {product.stock}</p>
469
+ </div>
470
+ ))}
471
+ </div>
472
+ );
473
+ }
474
+
475
+ function ShoppingCart({ userId }: { userId: string }) {
476
+ const { cart, itemCount, addItem, updateItem, removeItem, checkout, getCartWithDetails } = useCart(ecommerce, userId);
477
+ const [detailedItems, setDetailedItems] = useState([]);
478
+
479
+ useEffect(() => {
480
+ // Load cart with product details
481
+ const loadDetails = async () => {
482
+ const items = await getCartWithDetails();
483
+ setDetailedItems(items);
484
+ };
485
+ loadDetails();
486
+ }, [getCartWithDetails]);
487
+
488
+ return (
489
+ <div>
490
+ <h2>Cart ({itemCount} items)</h2>
491
+ {detailedItems.map(item => (
492
+ <div key={item.productId}>
493
+ <h3>{item.product.name}</h3>
494
+ <p>${(item.product.price / 100).toFixed(2)} x {item.quantity}</p>
495
+ <p>Subtotal: ${(item.lineTotal / 100).toFixed(2)}</p>
496
+ <button onClick={() => updateItem(item.productId, item.quantity + 1)}>+</button>
497
+ <button onClick={() => updateItem(item.productId, item.quantity - 1)}>-</button>
498
+ <button onClick={() => removeItem(item.productId)}>Remove</button>
499
+ </div>
500
+ ))}
501
+ <button onClick={() => checkout(shippingAddress)}>Checkout</button>
502
+ </div>
503
+ );
504
+ }
505
+
506
+ function OrderHistory({ userId }: { userId: string }) {
507
+ const { orders, loading, updateStatus, cancelOrder } = useOrders(ecommerce, { userId });
508
+
509
+ if (loading) return <div>Loading...</div>;
510
+
511
+ return (
512
+ <div>
513
+ {orders.map(order => (
514
+ <div key={order.id}>
515
+ <h3>Order #{order.id}</h3>
516
+ <p>Status: {order.status}</p>
517
+ <p>Total: ${(order.total / 100).toFixed(2)}</p>
518
+ <ul>
519
+ {order.items.map(item => (
520
+ <li key={item.productId}>
521
+ {item.name} x {item.quantity} - ${(item.price / 100).toFixed(2)}
522
+ </li>
523
+ ))}
524
+ </ul>
525
+ </div>
526
+ ))}
527
+ </div>
528
+ );
529
+ }
530
+ ```
531
+
532
+ ### Database Schema
533
+
534
+ Create these tables in your database:
535
+
536
+ ```typescript
537
+ // Products table
538
+ interface ProductRow {
539
+ id: string;
540
+ name: string;
541
+ description?: string;
542
+ sku?: string;
543
+ price: number; // cents
544
+ currency: string;
545
+ images: string[]; // JSON array
546
+ stock: number;
547
+ isActive: boolean;
548
+ category?: string;
549
+ metadata?: Record<string, any>; // JSON
550
+ created_at: string;
551
+ updated_at: string;
552
+ }
553
+
554
+ // Orders table
555
+ interface OrderRow {
556
+ id: string;
557
+ userId: string;
558
+ status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';
559
+ items: OrderItem[]; // JSON array
560
+ subtotal: number;
561
+ tax: number;
562
+ shipping: number;
563
+ total: number;
564
+ shippingAddress: Address; // JSON
565
+ billingAddress?: Address; // JSON
566
+ paymentMethodId?: string;
567
+ stripePaymentIntentId?: string;
568
+ notes?: string;
569
+ created_at: string;
570
+ updated_at: string;
571
+ }
572
+
573
+ // Order Items table (for queries)
574
+ interface OrderItemRow {
575
+ id: string;
576
+ orderId: string;
577
+ productId: string;
578
+ name: string;
579
+ quantity: number;
580
+ price: number;
581
+ lineTotal: number;
582
+ created_at: string;
583
+ }
584
+
585
+ // Carts table
586
+ interface CartRow {
587
+ id: string;
588
+ userId: string;
589
+ productId: string;
590
+ quantity: number;
591
+ created_at: string;
592
+ updated_at: string;
593
+ }
594
+ ```
595
+
312
596
  ## API Reference
313
597
 
314
598
  ### VlibeBaseDatabase
@@ -236,8 +236,7 @@ interface UsageMetric {
236
236
  period: string;
237
237
  createdAt: string;
238
238
  }
239
- interface Product {
240
- id: string;
239
+ interface Product extends BaseRecord {
241
240
  name: string;
242
241
  description?: string;
243
242
  sku?: string;
@@ -247,19 +246,21 @@ interface Product {
247
246
  stock: number;
248
247
  isActive: boolean;
249
248
  category?: string;
250
- createdAt: string;
251
- updatedAt: string;
249
+ metadata?: Record<string, any>;
252
250
  }
253
- interface Order {
254
- id: string;
251
+ interface Order extends BaseRecord {
255
252
  userId: string;
256
253
  status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';
257
254
  items: OrderItem[];
258
255
  subtotal: number;
259
256
  tax: number;
257
+ shipping: number;
260
258
  total: number;
261
259
  shippingAddress?: Address;
262
- createdAt: string;
260
+ billingAddress?: Address;
261
+ paymentMethodId?: string;
262
+ stripePaymentIntentId?: string;
263
+ notes?: string;
263
264
  }
264
265
  interface OrderItem {
265
266
  productId: string;
@@ -279,6 +280,76 @@ interface CartItem {
279
280
  productId: string;
280
281
  quantity: number;
281
282
  }
283
+ interface CartItemWithProduct {
284
+ productId: string;
285
+ quantity: number;
286
+ product: Product;
287
+ lineTotal: number;
288
+ }
289
+ interface CreateProductInput {
290
+ name: string;
291
+ description?: string;
292
+ sku?: string;
293
+ price: number;
294
+ currency: string;
295
+ images?: string[];
296
+ stock: number;
297
+ isActive?: boolean;
298
+ category?: string;
299
+ metadata?: Record<string, any>;
300
+ }
301
+ interface CreateOrderInput {
302
+ userId: string;
303
+ items: Array<{
304
+ productId: string;
305
+ quantity: number;
306
+ }>;
307
+ shippingAddress: Address;
308
+ billingAddress?: Address;
309
+ paymentMethodId?: string;
310
+ notes?: string;
311
+ }
312
+ interface OrderCalculation {
313
+ subtotal: number;
314
+ tax: number;
315
+ shipping: number;
316
+ total: number;
317
+ items: Array<{
318
+ productId: string;
319
+ name: string;
320
+ price: number;
321
+ quantity: number;
322
+ lineTotal: number;
323
+ inStock: boolean;
324
+ }>;
325
+ }
326
+ interface RevenueStats {
327
+ totalRevenue: number;
328
+ totalOrders: number;
329
+ averageOrderValue: number;
330
+ period: {
331
+ start: string;
332
+ end: string;
333
+ };
334
+ trend: {
335
+ revenue: number;
336
+ orders: number;
337
+ };
338
+ }
339
+ interface ProductStats {
340
+ productId: string;
341
+ name: string;
342
+ totalSold: number;
343
+ revenue: number;
344
+ }
345
+ interface OrderStats {
346
+ pending: number;
347
+ processing: number;
348
+ shipped: number;
349
+ delivered: number;
350
+ cancelled: number;
351
+ averageOrderValue: number;
352
+ }
282
353
  /**
283
354
  * Standard API response
284
355
  */
@@ -564,4 +635,133 @@ declare class VlibeBaseAuth {
564
635
  getBaseUrl(): string;
565
636
  }
566
637
 
567
- export { type AppCategory as A, type BasePlan as B, type ConnectStatus as C, type DatabaseConfig as D, type FeatureFlag as F, type Media as M, type Order as O, type PaymentsConfig as P, type QueryOptions as Q, type RefundOptions as R, type Subscription as S, type Transaction as T, type UsageMetric as U, VlibeBaseDatabase as V, type CheckoutOptions as a, type CheckoutSession as b, VlibeBaseAuth as c, type VlibeBaseConfig as d, type AuthConfig as e, type ColumnType as f, type TableColumn as g, type TableSchema as h, type TableInfo as i, type BaseRecord as j, type RealtimePayload as k, type VlibeUser as l, type VerifyResponse as m, type AuthSession as n, type Page as o, type Product as p, type OrderItem as q, type Address as r, type CartItem as s, type ApiResponse as t, type PaginatedResponse as u, type UseCollectionReturn as v, type UseCollectionOptions as w, type UseKVReturn as x, type UseAuthReturn as y, type UsePaymentsReturn as z };
638
+ /**
639
+ * VlibeBaseEcommerce - E-commerce functionality for Vlibe Base apps
640
+ *
641
+ * Provides specialized methods for managing products, inventory, orders,
642
+ * shopping carts, and e-commerce analytics.
643
+ */
644
+ declare class VlibeBaseEcommerce {
645
+ private db;
646
+ constructor(db: VlibeBaseDatabase);
647
+ /**
648
+ * Create a new product
649
+ * Auto-generates SKU if not provided
650
+ */
651
+ createProduct(input: CreateProductInput): Promise<Product>;
652
+ /**
653
+ * Update an existing product
654
+ */
655
+ updateProduct(productId: string, updates: Partial<Product>): Promise<Product>;
656
+ /**
657
+ * Get a single product by ID
658
+ */
659
+ getProduct(productId: string): Promise<Product | null>;
660
+ /**
661
+ * List products with filtering and pagination
662
+ */
663
+ listProducts(options?: {
664
+ category?: string;
665
+ isActive?: boolean;
666
+ sortBy?: 'name' | 'price' | 'stock' | 'created_at';
667
+ limit?: number;
668
+ offset?: number;
669
+ }): Promise<{
670
+ products: Product[];
671
+ total: number;
672
+ }>;
673
+ /**
674
+ * Soft delete a product (sets isActive = false)
675
+ */
676
+ deleteProduct(productId: string): Promise<void>;
677
+ /**
678
+ * Update product inventory with atomic operations
679
+ */
680
+ updateInventory(productId: string, quantity: number, operation: 'set' | 'increment' | 'decrement'): Promise<Product>;
681
+ /**
682
+ * Get products below stock threshold
683
+ */
684
+ getLowStockProducts(threshold?: number): Promise<Product[]>;
685
+ /**
686
+ * Bulk update inventory for multiple products
687
+ */
688
+ bulkUpdateInventory(updates: Array<{
689
+ productId: string;
690
+ quantity: number;
691
+ operation: 'set' | 'increment' | 'decrement';
692
+ }>): Promise<Product[]>;
693
+ /**
694
+ * Calculate order totals from cart items
695
+ */
696
+ calculateOrderTotal(items: CartItem[]): Promise<OrderCalculation>;
697
+ /**
698
+ * Create an order from cart items
699
+ * Reduces inventory atomically
700
+ */
701
+ createOrder(input: CreateOrderInput): Promise<Order>;
702
+ /**
703
+ * Get an order by ID
704
+ */
705
+ getOrder(orderId: string): Promise<Order | null>;
706
+ /**
707
+ * List orders with filtering
708
+ */
709
+ listOrders(options?: {
710
+ userId?: string;
711
+ status?: Order['status'];
712
+ sortBy?: 'created_at' | 'total';
713
+ limit?: number;
714
+ offset?: number;
715
+ }): Promise<{
716
+ orders: Order[];
717
+ total: number;
718
+ }>;
719
+ /**
720
+ * Update order status
721
+ */
722
+ updateOrderStatus(orderId: string, status: Order['status']): Promise<Order>;
723
+ /**
724
+ * Cancel an order and optionally restore inventory
725
+ */
726
+ cancelOrder(orderId: string, restoreInventory?: boolean): Promise<Order>;
727
+ /**
728
+ * Add item to user's cart
729
+ */
730
+ addToCart(userId: string, item: CartItem): Promise<CartItem[]>;
731
+ /**
732
+ * Update cart item quantity or remove if quantity = 0
733
+ */
734
+ updateCartItem(userId: string, productId: string, quantity: number): Promise<CartItem[]>;
735
+ /**
736
+ * Get user's cart
737
+ */
738
+ getCart(userId: string): Promise<CartItem[]>;
739
+ /**
740
+ * Get user's cart with full product details
741
+ */
742
+ getCartWithDetails(userId: string): Promise<CartItemWithProduct[]>;
743
+ /**
744
+ * Clear user's cart
745
+ */
746
+ clearCart(userId: string): Promise<void>;
747
+ /**
748
+ * Checkout - convert cart to order and clear cart
749
+ */
750
+ checkout(userId: string, shippingAddress: Address, paymentMethodId?: string): Promise<Order>;
751
+ /**
752
+ * Get revenue statistics for a time period
753
+ */
754
+ getRevenueStats(period: 'day' | 'week' | 'month' | 'year'): Promise<RevenueStats>;
755
+ /**
756
+ * Get top selling products
757
+ */
758
+ getTopProducts(limit?: number, period?: 'day' | 'week' | 'month'): Promise<ProductStats[]>;
759
+ /**
760
+ * Get order statistics by status
761
+ */
762
+ getOrderStats(): Promise<OrderStats>;
763
+ private generateSKU;
764
+ private getPeriodStart;
765
+ }
766
+
767
+ export { type AppCategory as A, type BasePlan as B, type ConnectStatus as C, type DatabaseConfig as D, type OrderStats as E, type FeatureFlag as F, type ApiResponse as G, type PaginatedResponse as H, type UseCollectionReturn as I, type UseCollectionOptions as J, type UseKVReturn as K, type UseAuthReturn as L, type Media as M, type UsePaymentsReturn as N, type Order as O, type PaymentsConfig as P, type QueryOptions as Q, type RefundOptions as R, type Subscription as S, type Transaction as T, type UsageMetric as U, VlibeBaseDatabase as V, type CheckoutOptions as a, type CheckoutSession as b, VlibeBaseAuth as c, VlibeBaseEcommerce as d, type VlibeBaseConfig as e, type AuthConfig as f, type ColumnType as g, type TableColumn as h, type TableSchema as i, type TableInfo as j, type BaseRecord as k, type RealtimePayload as l, type VlibeUser as m, type VerifyResponse as n, type AuthSession as o, type Page as p, type Product as q, type OrderItem as r, type Address as s, type CartItem as t, type CartItemWithProduct as u, type CreateProductInput as v, type CreateOrderInput as w, type OrderCalculation as x, type RevenueStats as y, type ProductStats as z };