@stackbe/sdk 0.6.4 → 0.7.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/dist/index.js CHANGED
@@ -24,7 +24,10 @@ __export(index_exports, {
24
24
  CheckoutClient: () => CheckoutClient,
25
25
  CustomersClient: () => CustomersClient,
26
26
  EntitlementsClient: () => EntitlementsClient,
27
+ FeatureRequestsClient: () => FeatureRequestsClient,
27
28
  OrganizationsClient: () => OrganizationsClient,
29
+ PlansClient: () => PlansClient,
30
+ ProductsClient: () => ProductsClient,
28
31
  StackBE: () => StackBE,
29
32
  StackBEError: () => StackBEError,
30
33
  SubscriptionsClient: () => SubscriptionsClient,
@@ -618,7 +621,7 @@ var CheckoutClient = class {
618
621
  *
619
622
  * @example
620
623
  * ```typescript
621
- * // With new customer (will be created)
624
+ * // With customer email (looks up or creates customer)
622
625
  * const { url } = await stackbe.checkout.createSession({
623
626
  * customer: { email: 'user@example.com', name: 'John' },
624
627
  * planId: 'plan_pro_monthly',
@@ -626,6 +629,18 @@ var CheckoutClient = class {
626
629
  * trialDays: 14,
627
630
  * });
628
631
  * ```
632
+ *
633
+ * @example
634
+ * ```typescript
635
+ * // Organization-level subscription (B2B)
636
+ * const { url } = await stackbe.checkout.createSession({
637
+ * customer: 'cust_123',
638
+ * organizationId: 'org_456', // Customer must be owner/admin
639
+ * planId: 'plan_team',
640
+ * successUrl: 'https://myapp.com/success',
641
+ * cancelUrl: 'https://myapp.com/pricing',
642
+ * });
643
+ * ```
629
644
  */
630
645
  async createSession(options) {
631
646
  const body = {
@@ -633,15 +648,25 @@ var CheckoutClient = class {
633
648
  planId: options.planId,
634
649
  successUrl: options.successUrl,
635
650
  cancelUrl: options.cancelUrl,
651
+ organizationId: options.organizationId,
636
652
  allowPromotionCodes: options.allowPromotionCodes,
637
653
  trialDays: options.trialDays,
638
654
  metadata: options.metadata
639
655
  };
656
+ if (!options.customer) {
657
+ throw new Error(
658
+ 'customer is required. Use customer: "cust_xxx" for existing customer ID, or customer: { email: "user@example.com" } for email-based lookup.'
659
+ );
660
+ }
640
661
  if (typeof options.customer === "string") {
641
662
  body.customerId = options.customer;
642
- } else {
663
+ } else if (options.customer.email) {
643
664
  body.customerEmail = options.customer.email;
644
665
  body.customerName = options.customer.name;
666
+ } else {
667
+ throw new Error(
668
+ 'customer.email is required when using object form. Use customer: { email: "user@example.com" }'
669
+ );
645
670
  }
646
671
  return this.http.post("/v1/checkout/session", body);
647
672
  }
@@ -1333,6 +1358,297 @@ var OrganizationsClient = class {
1333
1358
  }
1334
1359
  };
1335
1360
 
1361
+ // src/plans.ts
1362
+ var PlansClient = class {
1363
+ constructor(http) {
1364
+ this.http = http;
1365
+ }
1366
+ /**
1367
+ * List all plans for the app.
1368
+ *
1369
+ * @example
1370
+ * ```typescript
1371
+ * // List all plans
1372
+ * const plans = await stackbe.plans.list();
1373
+ *
1374
+ * // Filter by product
1375
+ * const plans = await stackbe.plans.list({ productId: 'prod_123' });
1376
+ *
1377
+ * // Display in pricing page
1378
+ * plans.forEach(plan => {
1379
+ * console.log(`${plan.name}: $${plan.priceCents / 100}/${plan.interval}`);
1380
+ * });
1381
+ * ```
1382
+ */
1383
+ async list(options) {
1384
+ const params = new URLSearchParams();
1385
+ if (options?.productId) {
1386
+ params.set("productId", options.productId);
1387
+ }
1388
+ const query = params.toString();
1389
+ return this.http.get(`/v1/plans${query ? `?${query}` : ""}`);
1390
+ }
1391
+ /**
1392
+ * Get a plan by ID.
1393
+ *
1394
+ * @example
1395
+ * ```typescript
1396
+ * const plan = await stackbe.plans.get('plan_123');
1397
+ * console.log(plan.name, plan.priceCents, plan.entitlements);
1398
+ * ```
1399
+ */
1400
+ async get(planId) {
1401
+ return this.http.get(`/v1/plans/${planId}`);
1402
+ }
1403
+ /**
1404
+ * Get active plans only (excludes archived plans).
1405
+ *
1406
+ * @example
1407
+ * ```typescript
1408
+ * const activePlans = await stackbe.plans.getActive();
1409
+ * ```
1410
+ */
1411
+ async getActive(options) {
1412
+ const plans = await this.list(options);
1413
+ return plans.filter((p) => p.status === "active");
1414
+ }
1415
+ /**
1416
+ * Get plans sorted by price (ascending).
1417
+ *
1418
+ * @example
1419
+ * ```typescript
1420
+ * const plans = await stackbe.plans.listByPrice();
1421
+ * // [Free, Starter, Pro, Enterprise]
1422
+ * ```
1423
+ */
1424
+ async listByPrice(options) {
1425
+ const plans = await this.getActive(options);
1426
+ return plans.sort((a, b) => a.priceCents - b.priceCents);
1427
+ }
1428
+ };
1429
+ var ProductsClient = class {
1430
+ constructor(http, appId) {
1431
+ this.http = http;
1432
+ this.appId = appId;
1433
+ }
1434
+ /**
1435
+ * List all products for the app.
1436
+ *
1437
+ * @example
1438
+ * ```typescript
1439
+ * const products = await stackbe.products.list();
1440
+ * products.forEach(product => {
1441
+ * console.log(product.name, product.plans?.length, 'plans');
1442
+ * });
1443
+ * ```
1444
+ */
1445
+ async list(options) {
1446
+ const params = new URLSearchParams();
1447
+ params.set("appId", options?.appId ?? this.appId);
1448
+ return this.http.get(`/v1/products?${params.toString()}`);
1449
+ }
1450
+ /**
1451
+ * Get a product by ID.
1452
+ *
1453
+ * @example
1454
+ * ```typescript
1455
+ * const product = await stackbe.products.get('prod_123');
1456
+ * console.log(product.name, product.description);
1457
+ * ```
1458
+ */
1459
+ async get(productId) {
1460
+ return this.http.get(`/v1/products/${productId}`);
1461
+ }
1462
+ };
1463
+
1464
+ // src/feature-requests.ts
1465
+ var FeatureRequestsClient = class {
1466
+ constructor(http, appId) {
1467
+ this.http = http;
1468
+ this.appId = appId;
1469
+ }
1470
+ /**
1471
+ * List feature requests for the app.
1472
+ *
1473
+ * @example
1474
+ * ```typescript
1475
+ * // Get all feature requests
1476
+ * const { data, total } = await stackbe.featureRequests.list();
1477
+ *
1478
+ * // Filter by status
1479
+ * const planned = await stackbe.featureRequests.list({ status: 'planned' });
1480
+ *
1481
+ * // Sort by votes
1482
+ * const popular = await stackbe.featureRequests.list({ sortBy: 'votes' });
1483
+ * ```
1484
+ */
1485
+ async list(options = {}) {
1486
+ const params = {};
1487
+ if (options.status) params.status = options.status;
1488
+ if (options.category) params.category = options.category;
1489
+ if (options.sortBy) params.sortBy = options.sortBy;
1490
+ if (options.limit) params.limit = options.limit;
1491
+ if (options.offset) params.offset = options.offset;
1492
+ return this.http.get(
1493
+ `/v1/apps/${this.appId}/feature-requests`,
1494
+ params
1495
+ );
1496
+ }
1497
+ /**
1498
+ * Submit a new feature request.
1499
+ * Requires customer session token.
1500
+ *
1501
+ * @example
1502
+ * ```typescript
1503
+ * const request = await stackbe.featureRequests.create({
1504
+ * title: 'Dark mode support',
1505
+ * description: 'Would love to have a dark theme option',
1506
+ * category: 'UI',
1507
+ * });
1508
+ * ```
1509
+ */
1510
+ async create(options) {
1511
+ return this.http.post(
1512
+ `/v1/apps/${this.appId}/feature-requests`,
1513
+ options
1514
+ );
1515
+ }
1516
+ /**
1517
+ * Get a specific feature request by ID.
1518
+ *
1519
+ * @example
1520
+ * ```typescript
1521
+ * const request = await stackbe.featureRequests.get('req_123');
1522
+ * console.log(`${request.title} has ${request.voteCount} votes`);
1523
+ * ```
1524
+ */
1525
+ async get(requestId) {
1526
+ return this.http.get(
1527
+ `/v1/apps/${this.appId}/feature-requests/${requestId}`
1528
+ );
1529
+ }
1530
+ /**
1531
+ * Upvote a feature request.
1532
+ * Requires customer session token. Idempotent.
1533
+ *
1534
+ * @example
1535
+ * ```typescript
1536
+ * await stackbe.featureRequests.vote('req_123');
1537
+ * ```
1538
+ */
1539
+ async vote(requestId) {
1540
+ return this.http.post(
1541
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/vote`
1542
+ );
1543
+ }
1544
+ /**
1545
+ * Remove your vote from a feature request.
1546
+ * Requires customer session token.
1547
+ *
1548
+ * @example
1549
+ * ```typescript
1550
+ * await stackbe.featureRequests.removeVote('req_123');
1551
+ * ```
1552
+ */
1553
+ async removeVote(requestId) {
1554
+ return this.http.delete(
1555
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/vote`
1556
+ );
1557
+ }
1558
+ /**
1559
+ * Add a comment to a feature request.
1560
+ * Requires customer session token.
1561
+ *
1562
+ * @example
1563
+ * ```typescript
1564
+ * await stackbe.featureRequests.addComment('req_123', {
1565
+ * content: 'This would be really helpful for my workflow!',
1566
+ * });
1567
+ * ```
1568
+ */
1569
+ async addComment(requestId, options) {
1570
+ return this.http.post(
1571
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/comments`,
1572
+ options
1573
+ );
1574
+ }
1575
+ // ==================== Admin Methods ====================
1576
+ /**
1577
+ * Update a feature request status or category.
1578
+ * Requires API key (admin).
1579
+ *
1580
+ * @example
1581
+ * ```typescript
1582
+ * await stackbe.featureRequests.update('req_123', {
1583
+ * status: 'planned',
1584
+ * category: 'Core Features',
1585
+ * });
1586
+ * ```
1587
+ */
1588
+ async update(requestId, options) {
1589
+ return this.http.patch(
1590
+ `/v1/apps/${this.appId}/feature-requests/${requestId}`,
1591
+ options
1592
+ );
1593
+ }
1594
+ /**
1595
+ * Delete a feature request.
1596
+ * Requires API key (admin).
1597
+ *
1598
+ * @example
1599
+ * ```typescript
1600
+ * await stackbe.featureRequests.delete('req_123');
1601
+ * ```
1602
+ */
1603
+ async delete(requestId) {
1604
+ return this.http.delete(
1605
+ `/v1/apps/${this.appId}/feature-requests/${requestId}`
1606
+ );
1607
+ }
1608
+ /**
1609
+ * Get all customers interested in a feature request (author + voters).
1610
+ * Useful for user research or notifying users when the feature ships.
1611
+ * Requires API key (admin).
1612
+ *
1613
+ * @example
1614
+ * ```typescript
1615
+ * const { author, voters, totalInterested } = await stackbe.featureRequests.getInterestedCustomers('req_123');
1616
+ *
1617
+ * // Notify all interested users
1618
+ * const emails = [author.email, ...voters.map(v => v.email)];
1619
+ * await sendNotification(emails, 'Your requested feature is now live!');
1620
+ * ```
1621
+ */
1622
+ async getInterestedCustomers(requestId) {
1623
+ return this.http.get(
1624
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/interested`
1625
+ );
1626
+ }
1627
+ /**
1628
+ * Get a customer's feature request activity (requests submitted + votes).
1629
+ * Useful for displaying on customer profile.
1630
+ * Requires API key (admin).
1631
+ *
1632
+ * @example
1633
+ * ```typescript
1634
+ * const activity = await stackbe.featureRequests.getCustomerActivity('cust_123');
1635
+ *
1636
+ * console.log(`Submitted ${activity.totalSubmitted} requests`);
1637
+ * console.log(`Voted on ${activity.totalVotes} requests`);
1638
+ *
1639
+ * // Show their most wanted features
1640
+ * activity.votedOn.forEach(r => {
1641
+ * console.log(`- ${r.title} (${r.status})`);
1642
+ * });
1643
+ * ```
1644
+ */
1645
+ async getCustomerActivity(customerId) {
1646
+ return this.http.get(
1647
+ `/v1/apps/${this.appId}/feature-requests/customer/${customerId}/activity`
1648
+ );
1649
+ }
1650
+ };
1651
+
1336
1652
  // src/client.ts
1337
1653
  var DEFAULT_BASE_URL = "https://api.stackbe.io";
1338
1654
  var DEFAULT_TIMEOUT = 3e4;
@@ -1393,6 +1709,9 @@ var StackBE = class {
1393
1709
  devCallbackUrl: config.devCallbackUrl
1394
1710
  });
1395
1711
  this.organizations = new OrganizationsClient(this.http, config.appId);
1712
+ this.plans = new PlansClient(this.http);
1713
+ this.products = new ProductsClient(this.http, config.appId);
1714
+ this.featureRequests = new FeatureRequestsClient(this.http, config.appId);
1396
1715
  }
1397
1716
  /**
1398
1717
  * Create a middleware for Express that tracks usage automatically.
@@ -1530,7 +1849,10 @@ var StackBE = class {
1530
1849
  CheckoutClient,
1531
1850
  CustomersClient,
1532
1851
  EntitlementsClient,
1852
+ FeatureRequestsClient,
1533
1853
  OrganizationsClient,
1854
+ PlansClient,
1855
+ ProductsClient,
1534
1856
  StackBE,
1535
1857
  StackBEError,
1536
1858
  SubscriptionsClient,