@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/README.md +151 -9
- package/dist/index.d.mts +394 -3
- package/dist/index.d.ts +394 -3
- package/dist/index.js +324 -2
- package/dist/index.mjs +321 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -200,6 +200,64 @@ if (session) {
|
|
|
200
200
|
const isAuthenticated = await stackbe.auth.isAuthenticated(sessionToken);
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
+
### Plans & Products
|
|
204
|
+
|
|
205
|
+
List available pricing plans for your pricing page:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// List all plans
|
|
209
|
+
const plans = await stackbe.plans.list();
|
|
210
|
+
|
|
211
|
+
// List active plans sorted by price
|
|
212
|
+
const plans = await stackbe.plans.listByPrice();
|
|
213
|
+
// [Free ($0), Starter ($9), Pro ($29), Enterprise ($99)]
|
|
214
|
+
|
|
215
|
+
// Filter by product
|
|
216
|
+
const plans = await stackbe.plans.list({ productId: 'prod_123' });
|
|
217
|
+
|
|
218
|
+
// Get a specific plan
|
|
219
|
+
const plan = await stackbe.plans.get('plan_123');
|
|
220
|
+
console.log(plan.name, plan.priceCents, plan.entitlements);
|
|
221
|
+
|
|
222
|
+
// List products
|
|
223
|
+
const products = await stackbe.products.list();
|
|
224
|
+
|
|
225
|
+
// Get product details
|
|
226
|
+
const product = await stackbe.products.get('prod_123');
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### Dynamic Pricing Page Example
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// Next.js pricing page
|
|
233
|
+
export default async function PricingPage() {
|
|
234
|
+
const plans = await stackbe.plans.listByPrice();
|
|
235
|
+
|
|
236
|
+
return (
|
|
237
|
+
<div className="grid grid-cols-3 gap-4">
|
|
238
|
+
{plans.map((plan) => (
|
|
239
|
+
<div key={plan.id} className="border p-4 rounded">
|
|
240
|
+
<h3>{plan.name}</h3>
|
|
241
|
+
<p className="text-2xl">
|
|
242
|
+
${plan.priceCents / 100}/{plan.interval}
|
|
243
|
+
</p>
|
|
244
|
+
<ul>
|
|
245
|
+
{Object.entries(plan.entitlements).map(([key, value]) => (
|
|
246
|
+
<li key={key}>
|
|
247
|
+
{key}: {value === true ? '✓' : value}
|
|
248
|
+
</li>
|
|
249
|
+
))}
|
|
250
|
+
</ul>
|
|
251
|
+
<a href={`/checkout?plan=${plan.id}`}>
|
|
252
|
+
{plan.priceCents === 0 ? 'Start Free' : 'Subscribe'}
|
|
253
|
+
</a>
|
|
254
|
+
</div>
|
|
255
|
+
))}
|
|
256
|
+
</div>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
203
261
|
### Customer Management
|
|
204
262
|
|
|
205
263
|
```typescript
|
|
@@ -226,6 +284,76 @@ const customer = await stackbe.customers.getOrCreate({
|
|
|
226
284
|
await stackbe.customers.update('cust_123', { name: 'Jane Doe' });
|
|
227
285
|
```
|
|
228
286
|
|
|
287
|
+
### Organizations (B2B Multi-User)
|
|
288
|
+
|
|
289
|
+
Manage customer organizations for B2B apps:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// Create organization with customer as owner
|
|
293
|
+
const org = await stackbe.organizations.create({
|
|
294
|
+
name: 'Acme Corp',
|
|
295
|
+
ownerId: customer.id,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// List all organizations
|
|
299
|
+
const orgs = await stackbe.organizations.list();
|
|
300
|
+
|
|
301
|
+
// Get organization by ID
|
|
302
|
+
const org = await stackbe.organizations.get('org_123');
|
|
303
|
+
|
|
304
|
+
// Update organization
|
|
305
|
+
await stackbe.organizations.update('org_123', { name: 'New Name' });
|
|
306
|
+
|
|
307
|
+
// Delete organization (must have no active subscriptions)
|
|
308
|
+
await stackbe.organizations.delete('org_123');
|
|
309
|
+
|
|
310
|
+
// Add member to organization
|
|
311
|
+
await stackbe.organizations.addMember('org_123', {
|
|
312
|
+
customerId: 'cust_456',
|
|
313
|
+
role: 'member', // 'admin' | 'member'
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Remove member
|
|
317
|
+
await stackbe.organizations.removeMember('org_123', 'member_456');
|
|
318
|
+
|
|
319
|
+
// Update member role
|
|
320
|
+
await stackbe.organizations.updateMember('org_123', 'member_456', {
|
|
321
|
+
role: 'admin',
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Invite by email
|
|
325
|
+
await stackbe.organizations.invite('org_123', {
|
|
326
|
+
email: 'newuser@company.com',
|
|
327
|
+
role: 'member',
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// List pending invites
|
|
331
|
+
const invites = await stackbe.organizations.listInvites('org_123');
|
|
332
|
+
|
|
333
|
+
// Cancel invite
|
|
334
|
+
await stackbe.organizations.cancelInvite('org_123', 'invite_456');
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
#### B2B Signup Flow
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
async function signup(email: string, orgName: string) {
|
|
341
|
+
// 1. Get or create customer
|
|
342
|
+
const customer = await stackbe.customers.getOrCreate({ email });
|
|
343
|
+
|
|
344
|
+
// 2. Create organization with customer as owner
|
|
345
|
+
const org = await stackbe.organizations.create({
|
|
346
|
+
name: orgName,
|
|
347
|
+
ownerId: customer.id,
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// 3. Send magic link
|
|
351
|
+
await stackbe.auth.sendMagicLink(email);
|
|
352
|
+
|
|
353
|
+
return { customer, org };
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
229
357
|
## Express Middleware
|
|
230
358
|
|
|
231
359
|
### Track Usage Automatically
|
|
@@ -421,9 +549,22 @@ stackbe.auth.invalidateSession(token);
|
|
|
421
549
|
stackbe.auth.clearCache(); // Clear all
|
|
422
550
|
```
|
|
423
551
|
|
|
424
|
-
###
|
|
552
|
+
### Magic Link Callback URLs
|
|
425
553
|
|
|
426
|
-
|
|
554
|
+
**Recommended approach**: Pass the callback URL explicitly for maximum reliability:
|
|
555
|
+
|
|
556
|
+
```typescript
|
|
557
|
+
// Determine callback URL based on your environment
|
|
558
|
+
const callbackUrl = process.env.NODE_ENV === 'production'
|
|
559
|
+
? 'https://myapp.com/auth/callback'
|
|
560
|
+
: 'http://localhost:3000/auth/callback';
|
|
561
|
+
|
|
562
|
+
await stackbe.auth.sendMagicLink('user@example.com', {
|
|
563
|
+
redirectUrl: callbackUrl,
|
|
564
|
+
});
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Alternative**: Use `devCallbackUrl` for automatic detection (uses `devCallbackUrl` when `NODE_ENV !== 'production'`):
|
|
427
568
|
|
|
428
569
|
```typescript
|
|
429
570
|
const stackbe = new StackBE({
|
|
@@ -432,17 +573,18 @@ const stackbe = new StackBE({
|
|
|
432
573
|
devCallbackUrl: 'http://localhost:3000/auth/callback',
|
|
433
574
|
});
|
|
434
575
|
|
|
435
|
-
// In development
|
|
576
|
+
// In development, uses devCallbackUrl automatically
|
|
436
577
|
await stackbe.auth.sendMagicLink('user@example.com');
|
|
437
|
-
// Redirects to: http://localhost:3000/auth/callback
|
|
438
578
|
|
|
439
|
-
// In production,
|
|
440
|
-
//
|
|
441
|
-
await stackbe.auth.sendMagicLink('user@example.com', {
|
|
442
|
-
redirectUrl: 'https://myapp.com/custom-callback',
|
|
443
|
-
});
|
|
579
|
+
// In production, falls back to app settings callback URL
|
|
580
|
+
// Explicit redirectUrl always takes priority if provided
|
|
444
581
|
```
|
|
445
582
|
|
|
583
|
+
**Notes:**
|
|
584
|
+
- `devCallbackUrl` only activates when `NODE_ENV !== 'production'`
|
|
585
|
+
- Explicit `redirectUrl` parameter always takes priority
|
|
586
|
+
- For predictable behavior, use the explicit approach above
|
|
587
|
+
|
|
446
588
|
## Webhooks
|
|
447
589
|
|
|
448
590
|
Typed webhook payloads for handling StackBE events:
|
package/dist/index.d.mts
CHANGED
|
@@ -304,8 +304,43 @@ interface OrganizationInvite {
|
|
|
304
304
|
status: 'pending' | 'accepted' | 'cancelled';
|
|
305
305
|
sentAt: string;
|
|
306
306
|
}
|
|
307
|
+
interface Plan {
|
|
308
|
+
id: string;
|
|
309
|
+
name: string;
|
|
310
|
+
slug: string;
|
|
311
|
+
description?: string;
|
|
312
|
+
priceCents: number;
|
|
313
|
+
currency: string;
|
|
314
|
+
interval: 'month' | 'year';
|
|
315
|
+
trialDays?: number;
|
|
316
|
+
entitlements: Record<string, boolean | number | string>;
|
|
317
|
+
status: 'active' | 'archived';
|
|
318
|
+
requirePaymentMethod: boolean;
|
|
319
|
+
productId: string;
|
|
320
|
+
product?: Product;
|
|
321
|
+
createdAt: string;
|
|
322
|
+
updatedAt: string;
|
|
323
|
+
}
|
|
324
|
+
interface Product {
|
|
325
|
+
id: string;
|
|
326
|
+
name: string;
|
|
327
|
+
slug: string;
|
|
328
|
+
description?: string;
|
|
329
|
+
appId: string;
|
|
330
|
+
plans?: Plan[];
|
|
331
|
+
createdAt: string;
|
|
332
|
+
updatedAt: string;
|
|
333
|
+
}
|
|
334
|
+
interface ListPlansOptions {
|
|
335
|
+
/** Filter by product ID */
|
|
336
|
+
productId?: string;
|
|
337
|
+
}
|
|
338
|
+
interface ListProductsOptions {
|
|
339
|
+
/** Filter by app ID (defaults to SDK appId) */
|
|
340
|
+
appId?: string;
|
|
341
|
+
}
|
|
307
342
|
interface CreateCheckoutOptions {
|
|
308
|
-
/** Customer ID or email */
|
|
343
|
+
/** Customer ID or object with email. Use string for existing customer ID, object for email-based lookup/creation */
|
|
309
344
|
customer: string | {
|
|
310
345
|
email: string;
|
|
311
346
|
name?: string;
|
|
@@ -316,6 +351,8 @@ interface CreateCheckoutOptions {
|
|
|
316
351
|
successUrl: string;
|
|
317
352
|
/** URL to redirect if checkout is canceled */
|
|
318
353
|
cancelUrl?: string;
|
|
354
|
+
/** Organization ID for org-level subscriptions. Customer must be owner/admin of the org. */
|
|
355
|
+
organizationId?: string;
|
|
319
356
|
/** Allow promotion codes */
|
|
320
357
|
allowPromotionCodes?: boolean;
|
|
321
358
|
/** Trial period in days */
|
|
@@ -790,7 +827,7 @@ declare class CheckoutClient {
|
|
|
790
827
|
*
|
|
791
828
|
* @example
|
|
792
829
|
* ```typescript
|
|
793
|
-
* // With
|
|
830
|
+
* // With customer email (looks up or creates customer)
|
|
794
831
|
* const { url } = await stackbe.checkout.createSession({
|
|
795
832
|
* customer: { email: 'user@example.com', name: 'John' },
|
|
796
833
|
* planId: 'plan_pro_monthly',
|
|
@@ -798,6 +835,18 @@ declare class CheckoutClient {
|
|
|
798
835
|
* trialDays: 14,
|
|
799
836
|
* });
|
|
800
837
|
* ```
|
|
838
|
+
*
|
|
839
|
+
* @example
|
|
840
|
+
* ```typescript
|
|
841
|
+
* // Organization-level subscription (B2B)
|
|
842
|
+
* const { url } = await stackbe.checkout.createSession({
|
|
843
|
+
* customer: 'cust_123',
|
|
844
|
+
* organizationId: 'org_456', // Customer must be owner/admin
|
|
845
|
+
* planId: 'plan_team',
|
|
846
|
+
* successUrl: 'https://myapp.com/success',
|
|
847
|
+
* cancelUrl: 'https://myapp.com/pricing',
|
|
848
|
+
* });
|
|
849
|
+
* ```
|
|
801
850
|
*/
|
|
802
851
|
createSession(options: CreateCheckoutOptions): Promise<CheckoutSessionResponse>;
|
|
803
852
|
/**
|
|
@@ -1230,6 +1279,342 @@ declare class OrganizationsClient {
|
|
|
1230
1279
|
cancelInvite(orgId: string, inviteId: string): Promise<void>;
|
|
1231
1280
|
}
|
|
1232
1281
|
|
|
1282
|
+
/**
|
|
1283
|
+
* Client for managing plans and products.
|
|
1284
|
+
* Use this to list available pricing plans for display in your pricing page.
|
|
1285
|
+
*
|
|
1286
|
+
* @example
|
|
1287
|
+
* ```typescript
|
|
1288
|
+
* // List all plans
|
|
1289
|
+
* const plans = await stackbe.plans.list();
|
|
1290
|
+
*
|
|
1291
|
+
* // List plans for a specific product
|
|
1292
|
+
* const plans = await stackbe.plans.list({ productId: 'prod_123' });
|
|
1293
|
+
*
|
|
1294
|
+
* // Get a specific plan
|
|
1295
|
+
* const plan = await stackbe.plans.get('plan_123');
|
|
1296
|
+
*
|
|
1297
|
+
* // List products
|
|
1298
|
+
* const products = await stackbe.products.list();
|
|
1299
|
+
* ```
|
|
1300
|
+
*/
|
|
1301
|
+
declare class PlansClient {
|
|
1302
|
+
private readonly http;
|
|
1303
|
+
constructor(http: HttpClient);
|
|
1304
|
+
/**
|
|
1305
|
+
* List all plans for the app.
|
|
1306
|
+
*
|
|
1307
|
+
* @example
|
|
1308
|
+
* ```typescript
|
|
1309
|
+
* // List all plans
|
|
1310
|
+
* const plans = await stackbe.plans.list();
|
|
1311
|
+
*
|
|
1312
|
+
* // Filter by product
|
|
1313
|
+
* const plans = await stackbe.plans.list({ productId: 'prod_123' });
|
|
1314
|
+
*
|
|
1315
|
+
* // Display in pricing page
|
|
1316
|
+
* plans.forEach(plan => {
|
|
1317
|
+
* console.log(`${plan.name}: $${plan.priceCents / 100}/${plan.interval}`);
|
|
1318
|
+
* });
|
|
1319
|
+
* ```
|
|
1320
|
+
*/
|
|
1321
|
+
list(options?: ListPlansOptions): Promise<Plan[]>;
|
|
1322
|
+
/**
|
|
1323
|
+
* Get a plan by ID.
|
|
1324
|
+
*
|
|
1325
|
+
* @example
|
|
1326
|
+
* ```typescript
|
|
1327
|
+
* const plan = await stackbe.plans.get('plan_123');
|
|
1328
|
+
* console.log(plan.name, plan.priceCents, plan.entitlements);
|
|
1329
|
+
* ```
|
|
1330
|
+
*/
|
|
1331
|
+
get(planId: string): Promise<Plan>;
|
|
1332
|
+
/**
|
|
1333
|
+
* Get active plans only (excludes archived plans).
|
|
1334
|
+
*
|
|
1335
|
+
* @example
|
|
1336
|
+
* ```typescript
|
|
1337
|
+
* const activePlans = await stackbe.plans.getActive();
|
|
1338
|
+
* ```
|
|
1339
|
+
*/
|
|
1340
|
+
getActive(options?: ListPlansOptions): Promise<Plan[]>;
|
|
1341
|
+
/**
|
|
1342
|
+
* Get plans sorted by price (ascending).
|
|
1343
|
+
*
|
|
1344
|
+
* @example
|
|
1345
|
+
* ```typescript
|
|
1346
|
+
* const plans = await stackbe.plans.listByPrice();
|
|
1347
|
+
* // [Free, Starter, Pro, Enterprise]
|
|
1348
|
+
* ```
|
|
1349
|
+
*/
|
|
1350
|
+
listByPrice(options?: ListPlansOptions): Promise<Plan[]>;
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Client for managing products.
|
|
1354
|
+
*
|
|
1355
|
+
* @example
|
|
1356
|
+
* ```typescript
|
|
1357
|
+
* // List all products
|
|
1358
|
+
* const products = await stackbe.products.list();
|
|
1359
|
+
*
|
|
1360
|
+
* // Get a specific product
|
|
1361
|
+
* const product = await stackbe.products.get('prod_123');
|
|
1362
|
+
* ```
|
|
1363
|
+
*/
|
|
1364
|
+
declare class ProductsClient {
|
|
1365
|
+
private readonly http;
|
|
1366
|
+
private readonly appId;
|
|
1367
|
+
constructor(http: HttpClient, appId: string);
|
|
1368
|
+
/**
|
|
1369
|
+
* List all products for the app.
|
|
1370
|
+
*
|
|
1371
|
+
* @example
|
|
1372
|
+
* ```typescript
|
|
1373
|
+
* const products = await stackbe.products.list();
|
|
1374
|
+
* products.forEach(product => {
|
|
1375
|
+
* console.log(product.name, product.plans?.length, 'plans');
|
|
1376
|
+
* });
|
|
1377
|
+
* ```
|
|
1378
|
+
*/
|
|
1379
|
+
list(options?: ListProductsOptions): Promise<Product[]>;
|
|
1380
|
+
/**
|
|
1381
|
+
* Get a product by ID.
|
|
1382
|
+
*
|
|
1383
|
+
* @example
|
|
1384
|
+
* ```typescript
|
|
1385
|
+
* const product = await stackbe.products.get('prod_123');
|
|
1386
|
+
* console.log(product.name, product.description);
|
|
1387
|
+
* ```
|
|
1388
|
+
*/
|
|
1389
|
+
get(productId: string): Promise<Product>;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
interface FeatureRequest {
|
|
1393
|
+
id: string;
|
|
1394
|
+
title: string;
|
|
1395
|
+
description?: string;
|
|
1396
|
+
status: 'new' | 'under_review' | 'planned' | 'in_progress' | 'completed' | 'declined';
|
|
1397
|
+
category?: string;
|
|
1398
|
+
authorId: string;
|
|
1399
|
+
authorEmail: string;
|
|
1400
|
+
voteCount: number;
|
|
1401
|
+
hasVoted?: boolean;
|
|
1402
|
+
createdAt: string;
|
|
1403
|
+
updatedAt: string;
|
|
1404
|
+
}
|
|
1405
|
+
interface FeatureRequestComment {
|
|
1406
|
+
id: string;
|
|
1407
|
+
customerEmail: string;
|
|
1408
|
+
content: string;
|
|
1409
|
+
isAdminReply: boolean;
|
|
1410
|
+
createdAt: string;
|
|
1411
|
+
}
|
|
1412
|
+
interface CreateFeatureRequestOptions {
|
|
1413
|
+
title: string;
|
|
1414
|
+
description?: string;
|
|
1415
|
+
category?: string;
|
|
1416
|
+
}
|
|
1417
|
+
interface ListFeatureRequestsOptions {
|
|
1418
|
+
status?: 'new' | 'under_review' | 'planned' | 'in_progress' | 'completed' | 'declined';
|
|
1419
|
+
category?: string;
|
|
1420
|
+
sortBy?: 'newest' | 'votes' | 'recent_activity';
|
|
1421
|
+
limit?: number;
|
|
1422
|
+
offset?: number;
|
|
1423
|
+
}
|
|
1424
|
+
interface FeatureRequestListResponse {
|
|
1425
|
+
data: FeatureRequest[];
|
|
1426
|
+
total: number;
|
|
1427
|
+
limit: number;
|
|
1428
|
+
offset: number;
|
|
1429
|
+
}
|
|
1430
|
+
interface InterestedCustomer {
|
|
1431
|
+
customerId: string;
|
|
1432
|
+
email: string;
|
|
1433
|
+
votedAt?: string;
|
|
1434
|
+
submittedAt?: string;
|
|
1435
|
+
}
|
|
1436
|
+
interface InterestedCustomersResponse {
|
|
1437
|
+
featureRequestId: string;
|
|
1438
|
+
title: string;
|
|
1439
|
+
status: string;
|
|
1440
|
+
author: {
|
|
1441
|
+
customerId: string;
|
|
1442
|
+
email: string;
|
|
1443
|
+
submittedAt: string;
|
|
1444
|
+
};
|
|
1445
|
+
voters: InterestedCustomer[];
|
|
1446
|
+
totalInterested: number;
|
|
1447
|
+
}
|
|
1448
|
+
interface CustomerFeatureActivity {
|
|
1449
|
+
customerId: string;
|
|
1450
|
+
submitted: Array<{
|
|
1451
|
+
id: string;
|
|
1452
|
+
title: string;
|
|
1453
|
+
status: string;
|
|
1454
|
+
voteCount: number;
|
|
1455
|
+
submittedAt: string;
|
|
1456
|
+
}>;
|
|
1457
|
+
votedOn: Array<{
|
|
1458
|
+
id: string;
|
|
1459
|
+
title: string;
|
|
1460
|
+
status: string;
|
|
1461
|
+
voteCount: number;
|
|
1462
|
+
votedAt: string;
|
|
1463
|
+
}>;
|
|
1464
|
+
totalSubmitted: number;
|
|
1465
|
+
totalVotes: number;
|
|
1466
|
+
}
|
|
1467
|
+
declare class FeatureRequestsClient {
|
|
1468
|
+
private http;
|
|
1469
|
+
private appId;
|
|
1470
|
+
constructor(http: HttpClient, appId: string);
|
|
1471
|
+
/**
|
|
1472
|
+
* List feature requests for the app.
|
|
1473
|
+
*
|
|
1474
|
+
* @example
|
|
1475
|
+
* ```typescript
|
|
1476
|
+
* // Get all feature requests
|
|
1477
|
+
* const { data, total } = await stackbe.featureRequests.list();
|
|
1478
|
+
*
|
|
1479
|
+
* // Filter by status
|
|
1480
|
+
* const planned = await stackbe.featureRequests.list({ status: 'planned' });
|
|
1481
|
+
*
|
|
1482
|
+
* // Sort by votes
|
|
1483
|
+
* const popular = await stackbe.featureRequests.list({ sortBy: 'votes' });
|
|
1484
|
+
* ```
|
|
1485
|
+
*/
|
|
1486
|
+
list(options?: ListFeatureRequestsOptions): Promise<FeatureRequestListResponse>;
|
|
1487
|
+
/**
|
|
1488
|
+
* Submit a new feature request.
|
|
1489
|
+
* Requires customer session token.
|
|
1490
|
+
*
|
|
1491
|
+
* @example
|
|
1492
|
+
* ```typescript
|
|
1493
|
+
* const request = await stackbe.featureRequests.create({
|
|
1494
|
+
* title: 'Dark mode support',
|
|
1495
|
+
* description: 'Would love to have a dark theme option',
|
|
1496
|
+
* category: 'UI',
|
|
1497
|
+
* });
|
|
1498
|
+
* ```
|
|
1499
|
+
*/
|
|
1500
|
+
create(options: CreateFeatureRequestOptions): Promise<FeatureRequest>;
|
|
1501
|
+
/**
|
|
1502
|
+
* Get a specific feature request by ID.
|
|
1503
|
+
*
|
|
1504
|
+
* @example
|
|
1505
|
+
* ```typescript
|
|
1506
|
+
* const request = await stackbe.featureRequests.get('req_123');
|
|
1507
|
+
* console.log(`${request.title} has ${request.voteCount} votes`);
|
|
1508
|
+
* ```
|
|
1509
|
+
*/
|
|
1510
|
+
get(requestId: string): Promise<FeatureRequest & {
|
|
1511
|
+
comments: FeatureRequestComment[];
|
|
1512
|
+
}>;
|
|
1513
|
+
/**
|
|
1514
|
+
* Upvote a feature request.
|
|
1515
|
+
* Requires customer session token. Idempotent.
|
|
1516
|
+
*
|
|
1517
|
+
* @example
|
|
1518
|
+
* ```typescript
|
|
1519
|
+
* await stackbe.featureRequests.vote('req_123');
|
|
1520
|
+
* ```
|
|
1521
|
+
*/
|
|
1522
|
+
vote(requestId: string): Promise<{
|
|
1523
|
+
success?: boolean;
|
|
1524
|
+
alreadyVoted?: boolean;
|
|
1525
|
+
voteCount: number;
|
|
1526
|
+
}>;
|
|
1527
|
+
/**
|
|
1528
|
+
* Remove your vote from a feature request.
|
|
1529
|
+
* Requires customer session token.
|
|
1530
|
+
*
|
|
1531
|
+
* @example
|
|
1532
|
+
* ```typescript
|
|
1533
|
+
* await stackbe.featureRequests.removeVote('req_123');
|
|
1534
|
+
* ```
|
|
1535
|
+
*/
|
|
1536
|
+
removeVote(requestId: string): Promise<{
|
|
1537
|
+
success: boolean;
|
|
1538
|
+
voteCount: number;
|
|
1539
|
+
}>;
|
|
1540
|
+
/**
|
|
1541
|
+
* Add a comment to a feature request.
|
|
1542
|
+
* Requires customer session token.
|
|
1543
|
+
*
|
|
1544
|
+
* @example
|
|
1545
|
+
* ```typescript
|
|
1546
|
+
* await stackbe.featureRequests.addComment('req_123', {
|
|
1547
|
+
* content: 'This would be really helpful for my workflow!',
|
|
1548
|
+
* });
|
|
1549
|
+
* ```
|
|
1550
|
+
*/
|
|
1551
|
+
addComment(requestId: string, options: {
|
|
1552
|
+
content: string;
|
|
1553
|
+
}): Promise<FeatureRequestComment>;
|
|
1554
|
+
/**
|
|
1555
|
+
* Update a feature request status or category.
|
|
1556
|
+
* Requires API key (admin).
|
|
1557
|
+
*
|
|
1558
|
+
* @example
|
|
1559
|
+
* ```typescript
|
|
1560
|
+
* await stackbe.featureRequests.update('req_123', {
|
|
1561
|
+
* status: 'planned',
|
|
1562
|
+
* category: 'Core Features',
|
|
1563
|
+
* });
|
|
1564
|
+
* ```
|
|
1565
|
+
*/
|
|
1566
|
+
update(requestId: string, options: {
|
|
1567
|
+
status?: string;
|
|
1568
|
+
category?: string;
|
|
1569
|
+
}): Promise<FeatureRequest>;
|
|
1570
|
+
/**
|
|
1571
|
+
* Delete a feature request.
|
|
1572
|
+
* Requires API key (admin).
|
|
1573
|
+
*
|
|
1574
|
+
* @example
|
|
1575
|
+
* ```typescript
|
|
1576
|
+
* await stackbe.featureRequests.delete('req_123');
|
|
1577
|
+
* ```
|
|
1578
|
+
*/
|
|
1579
|
+
delete(requestId: string): Promise<{
|
|
1580
|
+
success: boolean;
|
|
1581
|
+
}>;
|
|
1582
|
+
/**
|
|
1583
|
+
* Get all customers interested in a feature request (author + voters).
|
|
1584
|
+
* Useful for user research or notifying users when the feature ships.
|
|
1585
|
+
* Requires API key (admin).
|
|
1586
|
+
*
|
|
1587
|
+
* @example
|
|
1588
|
+
* ```typescript
|
|
1589
|
+
* const { author, voters, totalInterested } = await stackbe.featureRequests.getInterestedCustomers('req_123');
|
|
1590
|
+
*
|
|
1591
|
+
* // Notify all interested users
|
|
1592
|
+
* const emails = [author.email, ...voters.map(v => v.email)];
|
|
1593
|
+
* await sendNotification(emails, 'Your requested feature is now live!');
|
|
1594
|
+
* ```
|
|
1595
|
+
*/
|
|
1596
|
+
getInterestedCustomers(requestId: string): Promise<InterestedCustomersResponse>;
|
|
1597
|
+
/**
|
|
1598
|
+
* Get a customer's feature request activity (requests submitted + votes).
|
|
1599
|
+
* Useful for displaying on customer profile.
|
|
1600
|
+
* Requires API key (admin).
|
|
1601
|
+
*
|
|
1602
|
+
* @example
|
|
1603
|
+
* ```typescript
|
|
1604
|
+
* const activity = await stackbe.featureRequests.getCustomerActivity('cust_123');
|
|
1605
|
+
*
|
|
1606
|
+
* console.log(`Submitted ${activity.totalSubmitted} requests`);
|
|
1607
|
+
* console.log(`Voted on ${activity.totalVotes} requests`);
|
|
1608
|
+
*
|
|
1609
|
+
* // Show their most wanted features
|
|
1610
|
+
* activity.votedOn.forEach(r => {
|
|
1611
|
+
* console.log(`- ${r.title} (${r.status})`);
|
|
1612
|
+
* });
|
|
1613
|
+
* ```
|
|
1614
|
+
*/
|
|
1615
|
+
getCustomerActivity(customerId: string): Promise<CustomerFeatureActivity>;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1233
1618
|
declare class StackBE {
|
|
1234
1619
|
private http;
|
|
1235
1620
|
private appId;
|
|
@@ -1247,6 +1632,12 @@ declare class StackBE {
|
|
|
1247
1632
|
readonly auth: AuthClient;
|
|
1248
1633
|
/** Organization management (B2B multi-user) */
|
|
1249
1634
|
readonly organizations: OrganizationsClient;
|
|
1635
|
+
/** Pricing plans */
|
|
1636
|
+
readonly plans: PlansClient;
|
|
1637
|
+
/** Products */
|
|
1638
|
+
readonly products: ProductsClient;
|
|
1639
|
+
/** Feature requests and voting */
|
|
1640
|
+
readonly featureRequests: FeatureRequestsClient;
|
|
1250
1641
|
/**
|
|
1251
1642
|
* Create a new StackBE client.
|
|
1252
1643
|
*
|
|
@@ -1347,4 +1738,4 @@ declare class StackBE {
|
|
|
1347
1738
|
}): (req: any, res: any, next: any) => Promise<any>;
|
|
1348
1739
|
}
|
|
1349
1740
|
|
|
1350
|
-
export { type AddMemberOptions, type AnyWebhookEvent, AuthClient, type CancelSubscriptionOptions, type CancelSubscriptionResponse, type CheckEntitlementResponse, type CheckUsageResponse, CheckoutClient, type CheckoutSessionResponse, type CreateCheckoutOptions, type CreateCustomerOptions, type CreateOrganizationOptions, type Customer, type CustomerCreatedEvent, type CustomerUpdatedEvent, type CustomerUsageResponse, type CustomerWebhookPayload, type CustomerWithSubscription, CustomersClient, EntitlementsClient, type EntitlementsResponse, type InviteMemberOptions, type MagicLinkOptions, type MagicLinkResponse, type Organization, type OrganizationInvite, type OrganizationMember, OrganizationsClient, type PaymentFailedEvent, type PaymentSucceededEvent, type PaymentWebhookPayload, type SessionResponse, StackBE, type StackBEConfig, StackBEError, type StackBEErrorCode, type StackBEErrorResponse, type Subscription, type SubscriptionCancelledEvent, type SubscriptionCreatedEvent, type SubscriptionRenewedEvent, type SubscriptionUpdatedEvent, type SubscriptionWebhookPayload, type SubscriptionWithPlan, SubscriptionsClient, type TrackUsageOptions, type TrackUsageResponse, type TrialEndedEvent, type TrialStartedEvent, type UpdateCustomerOptions, type UpdateOrganizationOptions, type UpdateSubscriptionOptions, UsageClient, type UsageMetric, type VerifyTokenResponse, type WebhookEvent, type WebhookEventType };
|
|
1741
|
+
export { type AddMemberOptions, type AnyWebhookEvent, AuthClient, type CancelSubscriptionOptions, type CancelSubscriptionResponse, type CheckEntitlementResponse, type CheckUsageResponse, CheckoutClient, type CheckoutSessionResponse, type CreateCheckoutOptions, type CreateCustomerOptions, type CreateFeatureRequestOptions, type CreateOrganizationOptions, type Customer, type CustomerCreatedEvent, type CustomerFeatureActivity, type CustomerUpdatedEvent, type CustomerUsageResponse, type CustomerWebhookPayload, type CustomerWithSubscription, CustomersClient, EntitlementsClient, type EntitlementsResponse, type FeatureRequest, type FeatureRequestComment, type FeatureRequestListResponse, FeatureRequestsClient, type InterestedCustomer, type InterestedCustomersResponse, type InviteMemberOptions, type ListFeatureRequestsOptions, type ListPlansOptions, type ListProductsOptions, type MagicLinkOptions, type MagicLinkResponse, type Organization, type OrganizationInvite, type OrganizationMember, OrganizationsClient, type PaymentFailedEvent, type PaymentSucceededEvent, type PaymentWebhookPayload, type Plan, PlansClient, type Product, ProductsClient, type SessionResponse, StackBE, type StackBEConfig, StackBEError, type StackBEErrorCode, type StackBEErrorResponse, type Subscription, type SubscriptionCancelledEvent, type SubscriptionCreatedEvent, type SubscriptionRenewedEvent, type SubscriptionUpdatedEvent, type SubscriptionWebhookPayload, type SubscriptionWithPlan, SubscriptionsClient, type TrackUsageOptions, type TrackUsageResponse, type TrialEndedEvent, type TrialStartedEvent, type UpdateCustomerOptions, type UpdateOrganizationOptions, type UpdateSubscriptionOptions, UsageClient, type UsageMetric, type VerifyTokenResponse, type WebhookEvent, type WebhookEventType };
|