@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.
@@ -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 };