authtara-sdk 1.0.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,420 @@
1
+ # authtara-sdk
2
+
3
+ > **SDK Client untuk integrasi dengan DigitalSolution Platform** - SSO Authentication, Billing/Entitlement Check, dan Usage Metering untuk aplikasi external.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/authtara-sdk.svg)](https://www.npmjs.com/package/authtara-sdk)
6
+ [![CI](https://github.com/digitalsolution/authtara-sdk/workflows/CI/badge.svg)](https://github.com/digitalsolution/authtara-sdk/actions)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
+
9
+ ## ๐Ÿš€ Features
10
+
11
+ - **๐Ÿ” SSO Authentication** - Offline JWT verification dengan HS256 + App Secret
12
+ - **๐Ÿ’ณ Billing & Entitlement** - Check tenant access rights dan feature availability
13
+ - **๐Ÿ“Š Usage Metering** - Track usage untuk usage-based billing
14
+ - **๐ŸŽฏ Type-Safe** - Full TypeScript support dengan comprehensive types
15
+ - **โšก Modern** - Built dengan ES Modules, CommonJS, dan TypeScript definitions
16
+ - **๐Ÿงช Tested** - Comprehensive unit tests dengan 80%+ coverage
17
+
18
+ ## ๐Ÿ“ฆ Installation
19
+
20
+ ```bash
21
+ # Menggunakan Bun (recommended)
22
+ bun add authtara-sdk
23
+
24
+ # Menggunakan npm
25
+ npm install authtara-sdk
26
+
27
+ # Menggunakan yarn
28
+ yarn add authtara-sdk
29
+ ```
30
+
31
+ ## ๐Ÿ”ง Quick Start
32
+
33
+ ### 1. Initialize SDK
34
+
35
+ ```typescript
36
+ import { Authtara } from "authtara-sdk";
37
+
38
+ const ds = new Authtara({
39
+ apiKey: process.env.DS_APP_SECRET!, // Get from Developer Dashboard
40
+ endpoint: "https://api.digitalsolution.com", // Optional, defaults to production
41
+ });
42
+ ```
43
+
44
+ ### 2. Verify SSO Token (Offline)
45
+
46
+ ```typescript
47
+ // Di callback endpoint setelah SSO
48
+ const code = searchParams.get("code");
49
+ const result = await ds.auth.exchangeCode(code!);
50
+
51
+ // Simpan token ke session
52
+ session.set("ds_token", result.token);
53
+
54
+ // Verify token (offline, no network call)
55
+ const session = await ds.auth.verifySession(result.token);
56
+
57
+ console.log("User:", session.user);
58
+ console.log("Tenant:", session.tenant);
59
+ console.log("Plan:", session.subscription.plan);
60
+ ```
61
+
62
+ ### 3. Check Entitlement
63
+
64
+ ```typescript
65
+ // Basic access check
66
+ const access = await ds.billing.checkEntitlement({
67
+ tenantId: session.tenant!.id,
68
+ });
69
+
70
+ if (!access.granted) {
71
+ return redirect("/upgrade", { reason: access.reason });
72
+ }
73
+
74
+ // Feature-specific check
75
+ const canUseAI = await ds.billing.checkEntitlement({
76
+ tenantId: session.tenant!.id,
77
+ featureKey: "ai_generator",
78
+ });
79
+
80
+ if (!canUseAI.granted) {
81
+ throw new Error("AI feature not available in your plan");
82
+ }
83
+ ```
84
+
85
+ ### 4. Record Usage
86
+
87
+ ```typescript
88
+ // Record API call
89
+ await ds.metering.recordUsage({
90
+ tenantId: session.tenant!.id,
91
+ metricSlug: "api_call",
92
+ amount: 1,
93
+ });
94
+
95
+ // Batch recording
96
+ await ds.metering.recordUsage({
97
+ tenantId: session.tenant!.id,
98
+ metricSlug: "message_sent",
99
+ amount: 50,
100
+ });
101
+ ```
102
+
103
+ ## ๐Ÿ“š API Reference
104
+
105
+ ### `Authtara` Constructor
106
+
107
+ ```typescript
108
+ new Authtara(config: AuthtaraConfig)
109
+ ```
110
+
111
+ **Config Options:**
112
+
113
+ | Option | Type | Required | Default | Description |
114
+ | ---------- | -------- | -------- | --------------------------------- | ----------------------------------- |
115
+ | `apiKey` | `string` | โœ… Yes | - | App Secret dari Developer Dashboard |
116
+ | `endpoint` | `string` | No | `https://api.digitalsolution.com` | Base URL Platform API |
117
+ | `timeout` | `number` | No | `30000` | Request timeout dalam milliseconds |
118
+
119
+ ### Auth Module
120
+
121
+ #### `auth.verifySession(token: string)`
122
+
123
+ Verify JWT token secara offline menggunakan App Secret.
124
+
125
+ **Returns:** `Promise<SessionVerifyResult>`
126
+
127
+ ```typescript
128
+ interface SessionVerifyResult {
129
+ isValid: boolean;
130
+ user?: {
131
+ id: string;
132
+ email: string;
133
+ name: string | null;
134
+ };
135
+ tenant?: {
136
+ id: string;
137
+ name: string;
138
+ subdomain: string;
139
+ role: string;
140
+ };
141
+ subscription?: {
142
+ plan: string;
143
+ status: string;
144
+ };
145
+ }
146
+ ```
147
+
148
+ **Throws:**
149
+
150
+ - `InvalidTokenError` - Token invalid atau expired
151
+
152
+ ---
153
+
154
+ #### `auth.exchangeCode(code: string)`
155
+
156
+ Exchange authorization code untuk JWT token (server-to-server).
157
+
158
+ **Returns:** `Promise<ExchangeResult>`
159
+
160
+ ```typescript
161
+ interface ExchangeResult {
162
+ token: string;
163
+ expiresIn: number;
164
+ user: { id: string; email: string; name: string | null };
165
+ tenant: { id: string; name: string; subdomain: string; role: string };
166
+ subscription: { plan: string; status: string };
167
+ }
168
+ ```
169
+
170
+ **Throws:**
171
+
172
+ - `ConfigurationError` - Code tidak disediakan
173
+ - `ApiError` - Network atau API error
174
+
175
+ ### Billing Module
176
+
177
+ #### `billing.checkEntitlement(params: CheckEntitlementParams)`
178
+
179
+ Check apakah tenant memiliki akses ke aplikasi atau fitur spesifik.
180
+
181
+ **Params:**
182
+
183
+ ```typescript
184
+ interface CheckEntitlementParams {
185
+ tenantId: string; // Required
186
+ featureKey?: string; // Optional: untuk cek fitur spesifik
187
+ }
188
+ ```
189
+
190
+ **Returns:** `Promise<EntitlementResult>`
191
+
192
+ ```typescript
193
+ interface EntitlementResult {
194
+ granted: boolean;
195
+ reason?: string;
196
+ entitlement?: {
197
+ status: string;
198
+ subscription?: {
199
+ plan: string;
200
+ status: string;
201
+ };
202
+ };
203
+ }
204
+ ```
205
+
206
+ ### Metering Module
207
+
208
+ #### `metering.recordUsage(params: RecordUsageParams)`
209
+
210
+ Catat penggunaan untuk usage-based billing.
211
+
212
+ **Params:**
213
+
214
+ ```typescript
215
+ interface RecordUsageParams {
216
+ tenantId: string;
217
+ metricSlug: string; // e.g., 'api_call', 'message_sent'
218
+ amount: number; // Harus positif
219
+ timestamp?: string; // Optional ISO timestamp
220
+ }
221
+ ```
222
+
223
+ **Available Metrics:**
224
+
225
+ - `message_sent` - Pesan yang dikirim (agregasi bulanan)
226
+ - `api_call` - API calls (agregasi harian)
227
+ - `connection_active` - Koneksi aktif (agregasi harian)
228
+ - `websocket_connection` - WebSocket connections (agregasi harian)
229
+
230
+ **Returns:** `Promise<RecordUsageResult>`
231
+
232
+ ```typescript
233
+ interface RecordUsageResult {
234
+ success: boolean;
235
+ recordId?: string;
236
+ }
237
+ ```
238
+
239
+ ## ๐Ÿ”’ Error Handling
240
+
241
+ SDK menyediakan custom error classes untuk memudahkan error handling:
242
+
243
+ ```typescript
244
+ import { AuthtaraError, InvalidTokenError, EntitlementDeniedError, ApiError, ConfigurationError } from "authtara-sdk";
245
+
246
+ try {
247
+ const session = await ds.auth.verifySession(token);
248
+ } catch (error) {
249
+ if (error instanceof InvalidTokenError) {
250
+ // Token invalid atau expired - redirect ke login
251
+ return redirect("/login");
252
+ }
253
+
254
+ if (error instanceof ApiError) {
255
+ console.error("API Error:", error.statusCode, error.message);
256
+ }
257
+
258
+ if (error instanceof ConfigurationError) {
259
+ console.error("Configuration Error:", error.message);
260
+ }
261
+ }
262
+ ```
263
+
264
+ **Error Hierarchy:**
265
+
266
+ - `AuthtaraError` (base class)
267
+ - `InvalidTokenError` - Token validation errors
268
+ - `EntitlementDeniedError` - Access denied errors
269
+ - `ApiError` - API communication errors
270
+ - `ConfigurationError` - SDK misconfiguration
271
+
272
+ ## ๐Ÿ› ๏ธ Advanced Usage
273
+
274
+ ### Custom Timeout
275
+
276
+ ```typescript
277
+ const ds = new Authtara({
278
+ apiKey: process.env.DS_APP_SECRET!,
279
+ timeout: 10000, // 10 seconds
280
+ });
281
+ ```
282
+
283
+ ### Environment Variables
284
+
285
+ Recommended `.env` setup:
286
+
287
+ ```bash
288
+ DS_APP_SECRET=your_app_secret_here
289
+ DS_API_URL=https://api.digitalsolution.com
290
+ ```
291
+
292
+ ### TypeScript Configuration
293
+
294
+ SDK mendukung TypeScript dengan strict mode. Pastikan `tsconfig.json` Anda memiliki:
295
+
296
+ ```json
297
+ {
298
+ "compilerOptions": {
299
+ "moduleResolution": "bundler",
300
+ "esModuleInterop": true
301
+ }
302
+ }
303
+ ```
304
+
305
+ ## ๐Ÿงช Testing
306
+
307
+ Untuk testing aplikasi Anda dengan SDK:
308
+
309
+ ```typescript
310
+ import { vi } from "vitest";
311
+
312
+ // Mock Authtara SDK
313
+ vi.mock("authtara-sdk", () => ({
314
+ Authtara: vi.fn().mockImplementation(() => ({
315
+ auth: {
316
+ verifySession: vi.fn().mockResolvedValue({
317
+ isValid: true,
318
+ user: { id: "1", email: "test@example.com", name: "Test" },
319
+ tenant: { id: "1", name: "Test Tenant", subdomain: "test", role: "OWNER" },
320
+ }),
321
+ },
322
+ })),
323
+ }));
324
+ ```
325
+
326
+ ## ๐Ÿ“– Integration Examples
327
+
328
+ ### Next.js App Router
329
+
330
+ ```typescript
331
+ // app/api/sso/callback/route.ts
332
+ import { Authtara } from "authtara-sdk";
333
+
334
+ const ds = new Authtara({
335
+ apiKey: process.env.DS_APP_SECRET!,
336
+ });
337
+
338
+ export async function GET(request: Request) {
339
+ const { searchParams } = new URL(request.url);
340
+ const code = searchParams.get("code");
341
+
342
+ if (!code) {
343
+ return Response.json({ error: "Missing code" }, { status: 400 });
344
+ }
345
+
346
+ const result = await ds.auth.exchangeCode(code);
347
+
348
+ // Set session cookie
349
+ // ... your session logic
350
+
351
+ return Response.redirect("/dashboard");
352
+ }
353
+ ```
354
+
355
+ ### Express.js
356
+
357
+ ```typescript
358
+ import express from "express";
359
+ import { Authtara } from "authtara-sdk";
360
+
361
+ const app = express();
362
+ const ds = new Authtara({
363
+ apiKey: process.env.DS_APP_SECRET!,
364
+ });
365
+
366
+ app.get("/api/sso/callback", async (req, res) => {
367
+ const { code } = req.query;
368
+ const result = await ds.auth.exchangeCode(code as string);
369
+
370
+ req.session.token = result.token;
371
+ res.redirect("/dashboard");
372
+ });
373
+
374
+ app.use(async (req, res, next) => {
375
+ if (!req.session.token) return next();
376
+
377
+ try {
378
+ const session = await ds.auth.verifySession(req.session.token);
379
+ req.user = session.user;
380
+ req.tenant = session.tenant;
381
+ next();
382
+ } catch (error) {
383
+ req.session.destroy();
384
+ res.redirect("/login");
385
+ }
386
+ });
387
+ ```
388
+
389
+ ## ๐Ÿ”„ Migration Guide
390
+
391
+ ### From v0.x to v1.x
392
+
393
+ Tidak ada breaking changes - v1.0.0 adalah initial stable release.
394
+
395
+ ## ๐Ÿ“ Changelog
396
+
397
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
398
+
399
+ ## ๐Ÿค Contributing
400
+
401
+ SDK ini di-maintain oleh DigitalSolution Team. Untuk bug reports atau feature requests:
402
+
403
+ 1. Check existing [GitHub Issues](https://github.com/digitalsolution/authtara-sdk/issues)
404
+ 2. Create new issue dengan detail yang lengkap
405
+ 3. Atau hubungi support di support@digitalsolution.com
406
+
407
+ ## ๐Ÿ“„ License
408
+
409
+ MIT License - see [LICENSE](LICENSE) file for details.
410
+
411
+ ## ๐Ÿ”— Links
412
+
413
+ - **NPM Package:** https://www.npmjs.com/package/authtara-sdk
414
+ - **GitHub Repository:** https://github.com/digitalsolution/authtara-sdk
415
+ - **Documentation:** https://docs.digitalsolution.com/sdk
416
+ - **Developer Dashboard:** https://digitalsolution.com/dashboard/developer
417
+
418
+ ---
419
+
420
+ **Built with โค๏ธ by DigitalSolution Team**