@stackbe/sdk 0.1.0
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 +286 -0
- package/dist/index.d.mts +448 -0
- package/dist/index.d.ts +448 -0
- package/dist/index.js +592 -0
- package/dist/index.mjs +561 -0
- package/package.json +52 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
interface HttpClientConfig {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
appId: string;
|
|
5
|
+
timeout: number;
|
|
6
|
+
}
|
|
7
|
+
declare class HttpClient {
|
|
8
|
+
private config;
|
|
9
|
+
constructor(config: HttpClientConfig);
|
|
10
|
+
private request;
|
|
11
|
+
get<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T>;
|
|
12
|
+
post<T>(path: string, body?: unknown, params?: Record<string, string | number | undefined>): Promise<T>;
|
|
13
|
+
patch<T>(path: string, body?: unknown): Promise<T>;
|
|
14
|
+
delete<T>(path: string): Promise<T>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface StackBEConfig {
|
|
18
|
+
/** Your StackBE API key (starts with sk_) */
|
|
19
|
+
apiKey: string;
|
|
20
|
+
/** Your App ID from the StackBE dashboard */
|
|
21
|
+
appId: string;
|
|
22
|
+
/** Base URL for the API (default: https://api.stackbe.io) */
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
25
|
+
timeout?: number;
|
|
26
|
+
}
|
|
27
|
+
interface TrackUsageOptions {
|
|
28
|
+
/** Quantity to track (default: 1) */
|
|
29
|
+
quantity?: number;
|
|
30
|
+
/** Idempotency key to prevent duplicate tracking */
|
|
31
|
+
idempotencyKey?: string;
|
|
32
|
+
}
|
|
33
|
+
interface TrackUsageResponse {
|
|
34
|
+
success: boolean;
|
|
35
|
+
currentUsage: number;
|
|
36
|
+
limit: number | null;
|
|
37
|
+
remaining: number | null;
|
|
38
|
+
}
|
|
39
|
+
interface CheckUsageResponse {
|
|
40
|
+
/** Whether the customer is within their usage limits */
|
|
41
|
+
allowed: boolean;
|
|
42
|
+
/** Current usage for this billing period */
|
|
43
|
+
currentUsage: number;
|
|
44
|
+
/** The limit (null if unlimited) */
|
|
45
|
+
limit: number | null;
|
|
46
|
+
/** Remaining quota (null if unlimited) */
|
|
47
|
+
remaining: number | null;
|
|
48
|
+
/** When the usage counter resets */
|
|
49
|
+
resetAt?: string;
|
|
50
|
+
}
|
|
51
|
+
interface UsageMetric {
|
|
52
|
+
metric: string;
|
|
53
|
+
displayName: string;
|
|
54
|
+
unit: string;
|
|
55
|
+
currentUsage: number;
|
|
56
|
+
limit: number | null;
|
|
57
|
+
included: number;
|
|
58
|
+
remaining: number | null;
|
|
59
|
+
overageQuantity: number;
|
|
60
|
+
overageCost: number;
|
|
61
|
+
}
|
|
62
|
+
interface CustomerUsageResponse {
|
|
63
|
+
customerId: string;
|
|
64
|
+
billingPeriod: string;
|
|
65
|
+
metrics: UsageMetric[];
|
|
66
|
+
}
|
|
67
|
+
interface CheckEntitlementResponse {
|
|
68
|
+
/** Whether the customer has access to this feature */
|
|
69
|
+
hasAccess: boolean;
|
|
70
|
+
/** The customer's current plan name */
|
|
71
|
+
planName?: string;
|
|
72
|
+
/** Additional entitlement metadata */
|
|
73
|
+
metadata?: Record<string, unknown>;
|
|
74
|
+
}
|
|
75
|
+
interface EntitlementsResponse {
|
|
76
|
+
customerId: string;
|
|
77
|
+
planId: string;
|
|
78
|
+
planName: string;
|
|
79
|
+
entitlements: Record<string, boolean | number | string>;
|
|
80
|
+
}
|
|
81
|
+
interface Customer {
|
|
82
|
+
id: string;
|
|
83
|
+
email: string;
|
|
84
|
+
name?: string;
|
|
85
|
+
metadata?: Record<string, unknown>;
|
|
86
|
+
createdAt: string;
|
|
87
|
+
updatedAt: string;
|
|
88
|
+
}
|
|
89
|
+
interface Subscription {
|
|
90
|
+
id: string;
|
|
91
|
+
customerId: string;
|
|
92
|
+
planId: string;
|
|
93
|
+
planName: string;
|
|
94
|
+
status: 'active' | 'canceled' | 'past_due' | 'trialing' | 'paused';
|
|
95
|
+
currentPeriodStart: string;
|
|
96
|
+
currentPeriodEnd: string;
|
|
97
|
+
cancelAtPeriodEnd: boolean;
|
|
98
|
+
createdAt: string;
|
|
99
|
+
}
|
|
100
|
+
interface CustomerWithSubscription extends Customer {
|
|
101
|
+
subscription?: Subscription;
|
|
102
|
+
}
|
|
103
|
+
interface CreateCustomerOptions {
|
|
104
|
+
email: string;
|
|
105
|
+
name?: string;
|
|
106
|
+
metadata?: Record<string, unknown>;
|
|
107
|
+
}
|
|
108
|
+
interface UpdateCustomerOptions {
|
|
109
|
+
name?: string;
|
|
110
|
+
metadata?: Record<string, unknown>;
|
|
111
|
+
}
|
|
112
|
+
interface MagicLinkResponse {
|
|
113
|
+
success: boolean;
|
|
114
|
+
message: string;
|
|
115
|
+
}
|
|
116
|
+
interface VerifyTokenResponse {
|
|
117
|
+
valid: boolean;
|
|
118
|
+
customer?: Customer;
|
|
119
|
+
token?: string;
|
|
120
|
+
expiresAt?: string;
|
|
121
|
+
}
|
|
122
|
+
interface SessionResponse {
|
|
123
|
+
customer: Customer;
|
|
124
|
+
subscription?: Subscription;
|
|
125
|
+
entitlements: Record<string, boolean | number | string>;
|
|
126
|
+
}
|
|
127
|
+
interface StackBEErrorResponse {
|
|
128
|
+
statusCode: number;
|
|
129
|
+
message: string;
|
|
130
|
+
error: string;
|
|
131
|
+
}
|
|
132
|
+
declare class StackBEError extends Error {
|
|
133
|
+
readonly statusCode: number;
|
|
134
|
+
readonly code: string;
|
|
135
|
+
constructor(message: string, statusCode: number, code: string);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
declare class UsageClient {
|
|
139
|
+
private http;
|
|
140
|
+
constructor(http: HttpClient);
|
|
141
|
+
/**
|
|
142
|
+
* Track a usage event for a customer.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* // Track 1 API call
|
|
147
|
+
* await stackbe.usage.track('cust_123', 'api_calls');
|
|
148
|
+
*
|
|
149
|
+
* // Track 5 API calls
|
|
150
|
+
* await stackbe.usage.track('cust_123', 'api_calls', { quantity: 5 });
|
|
151
|
+
*
|
|
152
|
+
* // Track with idempotency key
|
|
153
|
+
* await stackbe.usage.track('cust_123', 'api_calls', {
|
|
154
|
+
* quantity: 1,
|
|
155
|
+
* idempotencyKey: 'req_abc123'
|
|
156
|
+
* });
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
track(customerId: string, metric: string, options?: TrackUsageOptions): Promise<TrackUsageResponse>;
|
|
160
|
+
/**
|
|
161
|
+
* Check if a customer is within their usage limits for a specific metric.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const { allowed, remaining } = await stackbe.usage.check('cust_123', 'api_calls');
|
|
166
|
+
*
|
|
167
|
+
* if (!allowed) {
|
|
168
|
+
* throw new Error('Usage limit exceeded');
|
|
169
|
+
* }
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
check(customerId: string, metric: string): Promise<CheckUsageResponse>;
|
|
173
|
+
/**
|
|
174
|
+
* Get complete usage summary for a customer across all metrics.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* const usage = await stackbe.usage.get('cust_123');
|
|
179
|
+
*
|
|
180
|
+
* for (const metric of usage.metrics) {
|
|
181
|
+
* console.log(`${metric.displayName}: ${metric.currentUsage}/${metric.limit}`);
|
|
182
|
+
* }
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
get(customerId: string, billingPeriod?: string): Promise<CustomerUsageResponse>;
|
|
186
|
+
/**
|
|
187
|
+
* Track usage and check limits in one call.
|
|
188
|
+
* Returns whether the action is allowed after tracking.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```typescript
|
|
192
|
+
* const result = await stackbe.usage.trackAndCheck('cust_123', 'api_calls');
|
|
193
|
+
*
|
|
194
|
+
* if (!result.allowed) {
|
|
195
|
+
* // Rollback or handle limit exceeded
|
|
196
|
+
* }
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
trackAndCheck(customerId: string, metric: string, options?: TrackUsageOptions): Promise<TrackUsageResponse & {
|
|
200
|
+
allowed: boolean;
|
|
201
|
+
}>;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
declare class EntitlementsClient {
|
|
205
|
+
private http;
|
|
206
|
+
constructor(http: HttpClient);
|
|
207
|
+
/**
|
|
208
|
+
* Check if a customer has access to a specific feature.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* const { hasAccess } = await stackbe.entitlements.check('cust_123', 'premium_export');
|
|
213
|
+
*
|
|
214
|
+
* if (!hasAccess) {
|
|
215
|
+
* return res.status(403).json({ error: 'Upgrade to access this feature' });
|
|
216
|
+
* }
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
check(customerId: string, feature: string): Promise<CheckEntitlementResponse>;
|
|
220
|
+
/**
|
|
221
|
+
* Get all entitlements for a customer based on their current plan.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* const { entitlements, planName } = await stackbe.entitlements.getAll('cust_123');
|
|
226
|
+
*
|
|
227
|
+
* console.log(`Customer is on ${planName} plan`);
|
|
228
|
+
* console.log('Features:', entitlements);
|
|
229
|
+
* // { premium_export: true, api_access: true, max_projects: 10 }
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
getAll(customerId: string): Promise<EntitlementsResponse>;
|
|
233
|
+
/**
|
|
234
|
+
* Check multiple features at once.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* const results = await stackbe.entitlements.checkMany('cust_123', [
|
|
239
|
+
* 'premium_export',
|
|
240
|
+
* 'api_access',
|
|
241
|
+
* 'advanced_analytics'
|
|
242
|
+
* ]);
|
|
243
|
+
*
|
|
244
|
+
* // { premium_export: true, api_access: true, advanced_analytics: false }
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
checkMany(customerId: string, features: string[]): Promise<Record<string, boolean>>;
|
|
248
|
+
/**
|
|
249
|
+
* Require a feature - throws if customer doesn't have access.
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* // Throws StackBEError if customer doesn't have access
|
|
254
|
+
* await stackbe.entitlements.require('cust_123', 'premium_export');
|
|
255
|
+
*
|
|
256
|
+
* // If we get here, customer has access
|
|
257
|
+
* performPremiumExport();
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
require(customerId: string, feature: string): Promise<void>;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
declare class CustomersClient {
|
|
264
|
+
private http;
|
|
265
|
+
constructor(http: HttpClient);
|
|
266
|
+
/**
|
|
267
|
+
* Get a customer by ID.
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```typescript
|
|
271
|
+
* const customer = await stackbe.customers.get('cust_123');
|
|
272
|
+
* console.log(customer.email);
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
get(customerId: string): Promise<CustomerWithSubscription>;
|
|
276
|
+
/**
|
|
277
|
+
* Get a customer by email.
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```typescript
|
|
281
|
+
* const customer = await stackbe.customers.getByEmail('user@example.com');
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
getByEmail(email: string): Promise<CustomerWithSubscription | null>;
|
|
285
|
+
/**
|
|
286
|
+
* Create a new customer.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```typescript
|
|
290
|
+
* const customer = await stackbe.customers.create({
|
|
291
|
+
* email: 'user@example.com',
|
|
292
|
+
* name: 'John Doe',
|
|
293
|
+
* metadata: { source: 'website' }
|
|
294
|
+
* });
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
create(options: CreateCustomerOptions): Promise<Customer>;
|
|
298
|
+
/**
|
|
299
|
+
* Update a customer.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```typescript
|
|
303
|
+
* const customer = await stackbe.customers.update('cust_123', {
|
|
304
|
+
* name: 'Jane Doe',
|
|
305
|
+
* metadata: { plan: 'enterprise' }
|
|
306
|
+
* });
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
update(customerId: string, options: UpdateCustomerOptions): Promise<Customer>;
|
|
310
|
+
/**
|
|
311
|
+
* Get or create a customer by email.
|
|
312
|
+
* Returns existing customer if found, creates new one if not.
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```typescript
|
|
316
|
+
* const customer = await stackbe.customers.getOrCreate({
|
|
317
|
+
* email: 'user@example.com',
|
|
318
|
+
* name: 'John Doe'
|
|
319
|
+
* });
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
getOrCreate(options: CreateCustomerOptions): Promise<Customer>;
|
|
323
|
+
/**
|
|
324
|
+
* Send a magic link to a customer for passwordless authentication.
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* ```typescript
|
|
328
|
+
* await stackbe.customers.sendMagicLink('user@example.com', {
|
|
329
|
+
* redirectUrl: 'https://myapp.com/dashboard'
|
|
330
|
+
* });
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
sendMagicLink(email: string, options?: {
|
|
334
|
+
redirectUrl?: string;
|
|
335
|
+
}): Promise<MagicLinkResponse>;
|
|
336
|
+
/**
|
|
337
|
+
* Get the current session for a customer token.
|
|
338
|
+
* Use this to validate tokens and get customer data.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```typescript
|
|
342
|
+
* const session = await stackbe.customers.getSession(token);
|
|
343
|
+
* console.log(session.customer.email);
|
|
344
|
+
* console.log(session.entitlements);
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
347
|
+
getSession(token: string): Promise<SessionResponse>;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
declare class StackBE {
|
|
351
|
+
private http;
|
|
352
|
+
/** Usage tracking and limits */
|
|
353
|
+
readonly usage: UsageClient;
|
|
354
|
+
/** Feature entitlements */
|
|
355
|
+
readonly entitlements: EntitlementsClient;
|
|
356
|
+
/** Customer management */
|
|
357
|
+
readonly customers: CustomersClient;
|
|
358
|
+
/**
|
|
359
|
+
* Create a new StackBE client.
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* ```typescript
|
|
363
|
+
* import { StackBE } from '@stackbe/sdk';
|
|
364
|
+
*
|
|
365
|
+
* const stackbe = new StackBE({
|
|
366
|
+
* apiKey: process.env.STACKBE_API_KEY!,
|
|
367
|
+
* appId: process.env.STACKBE_APP_ID!,
|
|
368
|
+
* });
|
|
369
|
+
*
|
|
370
|
+
* // Track usage
|
|
371
|
+
* await stackbe.usage.track('customer_123', 'api_calls');
|
|
372
|
+
*
|
|
373
|
+
* // Check entitlements
|
|
374
|
+
* const { hasAccess } = await stackbe.entitlements.check('customer_123', 'premium');
|
|
375
|
+
*
|
|
376
|
+
* // Get customer
|
|
377
|
+
* const customer = await stackbe.customers.get('customer_123');
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
constructor(config: StackBEConfig);
|
|
381
|
+
/**
|
|
382
|
+
* Create a middleware for Express that tracks usage automatically.
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* ```typescript
|
|
386
|
+
* import express from 'express';
|
|
387
|
+
* import { StackBE } from '@stackbe/sdk';
|
|
388
|
+
*
|
|
389
|
+
* const app = express();
|
|
390
|
+
* const stackbe = new StackBE({ apiKey: '...', appId: '...' });
|
|
391
|
+
*
|
|
392
|
+
* // Track all API calls
|
|
393
|
+
* app.use(stackbe.middleware({
|
|
394
|
+
* getCustomerId: (req) => req.user?.customerId,
|
|
395
|
+
* metric: 'api_calls',
|
|
396
|
+
* }));
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
middleware(options: {
|
|
400
|
+
getCustomerId: (req: any) => string | undefined;
|
|
401
|
+
metric: string;
|
|
402
|
+
skip?: (req: any) => boolean;
|
|
403
|
+
}): (req: any, res: any, next: any) => Promise<any>;
|
|
404
|
+
/**
|
|
405
|
+
* Create a middleware that requires a feature entitlement.
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* ```typescript
|
|
409
|
+
* // Require premium feature
|
|
410
|
+
* app.get('/api/export',
|
|
411
|
+
* stackbe.requireFeature({
|
|
412
|
+
* getCustomerId: (req) => req.user?.customerId,
|
|
413
|
+
* feature: 'premium_export',
|
|
414
|
+
* }),
|
|
415
|
+
* exportHandler
|
|
416
|
+
* );
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
requireFeature(options: {
|
|
420
|
+
getCustomerId: (req: any) => string | undefined;
|
|
421
|
+
feature: string;
|
|
422
|
+
onDenied?: (req: any, res: any) => void;
|
|
423
|
+
}): (req: any, res: any, next: any) => Promise<any>;
|
|
424
|
+
/**
|
|
425
|
+
* Create a middleware that enforces usage limits.
|
|
426
|
+
*
|
|
427
|
+
* @example
|
|
428
|
+
* ```typescript
|
|
429
|
+
* // Enforce API call limits
|
|
430
|
+
* app.use('/api',
|
|
431
|
+
* stackbe.enforceLimit({
|
|
432
|
+
* getCustomerId: (req) => req.user?.customerId,
|
|
433
|
+
* metric: 'api_calls',
|
|
434
|
+
* })
|
|
435
|
+
* );
|
|
436
|
+
* ```
|
|
437
|
+
*/
|
|
438
|
+
enforceLimit(options: {
|
|
439
|
+
getCustomerId: (req: any) => string | undefined;
|
|
440
|
+
metric: string;
|
|
441
|
+
onLimitExceeded?: (req: any, res: any, usage: {
|
|
442
|
+
current: number;
|
|
443
|
+
limit: number;
|
|
444
|
+
}) => void;
|
|
445
|
+
}): (req: any, res: any, next: any) => Promise<any>;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export { type CheckEntitlementResponse, type CheckUsageResponse, type CreateCustomerOptions, type Customer, type CustomerUsageResponse, type CustomerWithSubscription, CustomersClient, EntitlementsClient, type EntitlementsResponse, type MagicLinkResponse, type SessionResponse, StackBE, type StackBEConfig, StackBEError, type StackBEErrorResponse, type Subscription, type TrackUsageOptions, type TrackUsageResponse, type UpdateCustomerOptions, UsageClient, type UsageMetric, type VerifyTokenResponse };
|