@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 ADDED
@@ -0,0 +1,286 @@
1
+ # @stackbe/sdk
2
+
3
+ Official JavaScript/TypeScript SDK for [StackBE](https://stackbe.io) - the billing backend for your side project.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @stackbe/sdk
9
+ # or
10
+ yarn add @stackbe/sdk
11
+ # or
12
+ pnpm add @stackbe/sdk
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { StackBE } from '@stackbe/sdk';
19
+
20
+ const stackbe = new StackBE({
21
+ apiKey: process.env.STACKBE_API_KEY!,
22
+ appId: process.env.STACKBE_APP_ID!,
23
+ });
24
+
25
+ // Track usage
26
+ await stackbe.usage.track('customer_123', 'api_calls');
27
+
28
+ // Check if within limits
29
+ const { allowed, remaining } = await stackbe.usage.check('customer_123', 'api_calls');
30
+
31
+ // Check feature access
32
+ const { hasAccess } = await stackbe.entitlements.check('customer_123', 'premium_export');
33
+ ```
34
+
35
+ ## Usage Tracking
36
+
37
+ Track billable usage events for your customers:
38
+
39
+ ```typescript
40
+ // Track a single event
41
+ await stackbe.usage.track('customer_123', 'api_calls');
42
+
43
+ // Track multiple units
44
+ await stackbe.usage.track('customer_123', 'tokens', { quantity: 1500 });
45
+
46
+ // Check current usage
47
+ const usage = await stackbe.usage.get('customer_123');
48
+ console.log(usage.metrics);
49
+ // [{ metric: 'api_calls', currentUsage: 150, limit: 1000, remaining: 850 }]
50
+
51
+ // Check specific metric
52
+ const { allowed, remaining } = await stackbe.usage.check('customer_123', 'api_calls');
53
+ if (!allowed) {
54
+ throw new Error('Usage limit exceeded');
55
+ }
56
+
57
+ // Track and check in one call
58
+ const result = await stackbe.usage.trackAndCheck('customer_123', 'api_calls');
59
+ if (!result.allowed) {
60
+ // Handle limit exceeded
61
+ }
62
+ ```
63
+
64
+ ## Entitlements
65
+
66
+ Check feature access based on customer's plan:
67
+
68
+ ```typescript
69
+ // Check single feature
70
+ const { hasAccess } = await stackbe.entitlements.check('customer_123', 'premium_export');
71
+
72
+ if (!hasAccess) {
73
+ return res.status(403).json({ error: 'Upgrade to access this feature' });
74
+ }
75
+
76
+ // Get all entitlements
77
+ const { entitlements, planName } = await stackbe.entitlements.getAll('customer_123');
78
+ console.log(`Customer is on ${planName}`);
79
+ console.log(entitlements);
80
+ // { premium_export: true, api_access: true, max_projects: 10 }
81
+
82
+ // Check multiple features at once
83
+ const features = await stackbe.entitlements.checkMany('customer_123', [
84
+ 'premium_export',
85
+ 'advanced_analytics',
86
+ 'api_access'
87
+ ]);
88
+ // { premium_export: true, advanced_analytics: false, api_access: true }
89
+
90
+ // Require a feature (throws if not available)
91
+ await stackbe.entitlements.require('customer_123', 'premium_export');
92
+ ```
93
+
94
+ ## Customer Management
95
+
96
+ ```typescript
97
+ // Get customer
98
+ const customer = await stackbe.customers.get('customer_123');
99
+
100
+ // Get by email
101
+ const customer = await stackbe.customers.getByEmail('user@example.com');
102
+
103
+ // Create customer
104
+ const newCustomer = await stackbe.customers.create({
105
+ email: 'user@example.com',
106
+ name: 'John Doe',
107
+ metadata: { source: 'api' }
108
+ });
109
+
110
+ // Get or create (idempotent)
111
+ const customer = await stackbe.customers.getOrCreate({
112
+ email: 'user@example.com',
113
+ name: 'John Doe'
114
+ });
115
+
116
+ // Update customer
117
+ await stackbe.customers.update('customer_123', {
118
+ name: 'Jane Doe'
119
+ });
120
+ ```
121
+
122
+ ## Express Middleware
123
+
124
+ The SDK includes ready-to-use middleware for Express:
125
+
126
+ ### Track Usage Automatically
127
+
128
+ ```typescript
129
+ import express from 'express';
130
+ import { StackBE } from '@stackbe/sdk';
131
+
132
+ const app = express();
133
+ const stackbe = new StackBE({ apiKey: '...', appId: '...' });
134
+
135
+ // Track all API calls
136
+ app.use(stackbe.middleware({
137
+ getCustomerId: (req) => req.user?.customerId,
138
+ metric: 'api_calls',
139
+ skip: (req) => req.path === '/health', // Skip health checks
140
+ }));
141
+ ```
142
+
143
+ ### Require Feature Entitlements
144
+
145
+ ```typescript
146
+ // Protect premium endpoints
147
+ app.get('/api/export',
148
+ stackbe.requireFeature({
149
+ getCustomerId: (req) => req.user?.customerId,
150
+ feature: 'premium_export',
151
+ onDenied: (req, res) => {
152
+ res.status(403).json({ error: 'Upgrade to Pro to access exports' });
153
+ }
154
+ }),
155
+ exportHandler
156
+ );
157
+ ```
158
+
159
+ ### Enforce Usage Limits
160
+
161
+ ```typescript
162
+ // Block requests when limit exceeded
163
+ app.use('/api',
164
+ stackbe.enforceLimit({
165
+ getCustomerId: (req) => req.user?.customerId,
166
+ metric: 'api_calls',
167
+ onLimitExceeded: (req, res, { current, limit }) => {
168
+ res.status(429).json({
169
+ error: 'Rate limit exceeded',
170
+ current,
171
+ limit,
172
+ upgradeUrl: 'https://myapp.com/upgrade'
173
+ });
174
+ }
175
+ })
176
+ );
177
+ ```
178
+
179
+ ## Next.js Integration
180
+
181
+ ### API Routes (App Router)
182
+
183
+ ```typescript
184
+ // app/api/generate/route.ts
185
+ import { StackBE } from '@stackbe/sdk';
186
+ import { NextResponse } from 'next/server';
187
+
188
+ const stackbe = new StackBE({
189
+ apiKey: process.env.STACKBE_API_KEY!,
190
+ appId: process.env.STACKBE_APP_ID!,
191
+ });
192
+
193
+ export async function POST(request: Request) {
194
+ const { customerId } = await request.json();
195
+
196
+ // Check limits before processing
197
+ const { allowed, remaining } = await stackbe.usage.check(customerId, 'generations');
198
+
199
+ if (!allowed) {
200
+ return NextResponse.json(
201
+ { error: 'Generation limit reached', remaining: 0 },
202
+ { status: 429 }
203
+ );
204
+ }
205
+
206
+ // Track usage
207
+ await stackbe.usage.track(customerId, 'generations');
208
+
209
+ // Do the work...
210
+ const result = await generateSomething();
211
+
212
+ return NextResponse.json({ result, remaining: remaining! - 1 });
213
+ }
214
+ ```
215
+
216
+ ### Server Actions
217
+
218
+ ```typescript
219
+ // app/actions.ts
220
+ 'use server';
221
+
222
+ import { StackBE } from '@stackbe/sdk';
223
+
224
+ const stackbe = new StackBE({
225
+ apiKey: process.env.STACKBE_API_KEY!,
226
+ appId: process.env.STACKBE_APP_ID!,
227
+ });
228
+
229
+ export async function exportData(customerId: string) {
230
+ // Check feature access
231
+ const { hasAccess } = await stackbe.entitlements.check(customerId, 'data_export');
232
+
233
+ if (!hasAccess) {
234
+ throw new Error('Upgrade to Pro to export data');
235
+ }
236
+
237
+ // Perform export...
238
+ }
239
+ ```
240
+
241
+ ## Error Handling
242
+
243
+ ```typescript
244
+ import { StackBE, StackBEError } from '@stackbe/sdk';
245
+
246
+ try {
247
+ await stackbe.usage.track('customer_123', 'api_calls');
248
+ } catch (error) {
249
+ if (error instanceof StackBEError) {
250
+ console.error(`StackBE Error: ${error.message}`);
251
+ console.error(`Status: ${error.statusCode}`);
252
+ console.error(`Code: ${error.code}`);
253
+ }
254
+ }
255
+ ```
256
+
257
+ ## Configuration
258
+
259
+ ```typescript
260
+ const stackbe = new StackBE({
261
+ // Required
262
+ apiKey: 'sk_live_...', // Your API key
263
+ appId: 'app_...', // Your App ID
264
+
265
+ // Optional
266
+ baseUrl: 'https://api.stackbe.io', // API base URL
267
+ timeout: 30000, // Request timeout in ms
268
+ });
269
+ ```
270
+
271
+ ## TypeScript
272
+
273
+ The SDK is written in TypeScript and includes full type definitions:
274
+
275
+ ```typescript
276
+ import type {
277
+ Customer,
278
+ Subscription,
279
+ TrackUsageResponse,
280
+ CheckEntitlementResponse,
281
+ } from '@stackbe/sdk';
282
+ ```
283
+
284
+ ## License
285
+
286
+ MIT