@licenseseat/js 0.2.1 → 0.3.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 +279 -118
- package/dist/index.js +197 -142
- package/dist/types/LicenseSeat.d.ts +26 -16
- package/dist/types/LicenseSeat.d.ts.map +1 -1
- package/dist/types/cache.d.ts +10 -10
- package/dist/types/cache.d.ts.map +1 -1
- package/dist/types/types.d.ts +291 -63
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils.d.ts +5 -3
- package/dist/types/utils.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/LicenseSeat.js +194 -144
- package/src/cache.js +16 -18
- package/src/types.js +126 -34
- package/src/utils.js +31 -6
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# LicenseSeat JavaScript SDK
|
|
2
|
-
|
|
3
|
-
Official JavaScript/TypeScript SDK for [LicenseSeat](https://licenseseat.com) – the simple, secure licensing platform for apps, games, and plugins.
|
|
1
|
+
# LicenseSeat - JavaScript SDK
|
|
4
2
|
|
|
5
3
|
[](https://github.com/licenseseat/licenseseat-js/actions/workflows/ci.yml)
|
|
6
4
|
[](https://www.npmjs.com/package/@licenseseat/js)
|
|
7
|
-
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
The official JavaScript/TypeScript SDK for [LicenseSeat](https://licenseseat.com) – the simple, secure licensing platform for apps, games, and plugins.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -43,7 +43,10 @@ pnpm add @licenseseat/js
|
|
|
43
43
|
<script type="module">
|
|
44
44
|
import LicenseSeat from 'https://esm.sh/@licenseseat/js';
|
|
45
45
|
|
|
46
|
-
const sdk = new LicenseSeat({
|
|
46
|
+
const sdk = new LicenseSeat({
|
|
47
|
+
apiKey: 'your-api-key',
|
|
48
|
+
productSlug: 'your-product'
|
|
49
|
+
});
|
|
47
50
|
</script>
|
|
48
51
|
|
|
49
52
|
<!-- ESM via unpkg -->
|
|
@@ -69,6 +72,7 @@ import LicenseSeat from '@licenseseat/js';
|
|
|
69
72
|
// Create SDK instance
|
|
70
73
|
const sdk = new LicenseSeat({
|
|
71
74
|
apiKey: 'your-api-key',
|
|
75
|
+
productSlug: 'your-product', // Required: Your product slug
|
|
72
76
|
debug: true
|
|
73
77
|
});
|
|
74
78
|
|
|
@@ -98,6 +102,7 @@ import LicenseSeat, {
|
|
|
98
102
|
|
|
99
103
|
const config: LicenseSeatConfig = {
|
|
100
104
|
apiKey: 'your-api-key',
|
|
105
|
+
productSlug: 'your-product',
|
|
101
106
|
debug: true
|
|
102
107
|
};
|
|
103
108
|
|
|
@@ -117,11 +122,14 @@ TypeScript users get full type support automatically – the package includes ge
|
|
|
117
122
|
|
|
118
123
|
```javascript
|
|
119
124
|
const sdk = new LicenseSeat({
|
|
125
|
+
// Required
|
|
126
|
+
productSlug: 'your-product', // Your product slug from LicenseSeat dashboard
|
|
127
|
+
|
|
120
128
|
// Required for authenticated operations
|
|
121
129
|
apiKey: 'your-api-key',
|
|
122
130
|
|
|
123
131
|
// API Configuration
|
|
124
|
-
apiBaseUrl: 'https://licenseseat.com/api', // Default
|
|
132
|
+
apiBaseUrl: 'https://licenseseat.com/api/v1', // Default
|
|
125
133
|
|
|
126
134
|
// Storage
|
|
127
135
|
storagePrefix: 'licenseseat_', // localStorage key prefix
|
|
@@ -148,18 +156,19 @@ const sdk = new LicenseSeat({
|
|
|
148
156
|
|
|
149
157
|
### Configuration Options
|
|
150
158
|
|
|
151
|
-
| Option
|
|
152
|
-
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
159
|
+
| Option | Type | Default | Description |
|
|
160
|
+
| ------------------------ | --------- | ---------------------------------- | --------------------------------------------------------- |
|
|
161
|
+
| `productSlug` | `string` | – | **Required.** Your product slug from the dashboard |
|
|
162
|
+
| `apiKey` | `string` | `null` | API key for authentication (required for most operations) |
|
|
163
|
+
| `apiBaseUrl` | `string` | `'https://licenseseat.com/api/v1'` | API base URL |
|
|
164
|
+
| `storagePrefix` | `string` | `'licenseseat_'` | Prefix for localStorage keys |
|
|
165
|
+
| `autoValidateInterval` | `number` | `3600000` | Auto-validation interval in ms (1 hour) |
|
|
166
|
+
| `autoInitialize` | `boolean` | `true` | Auto-initialize and validate cached license |
|
|
167
|
+
| `offlineFallbackEnabled` | `boolean` | `false` | Enable offline validation on network errors |
|
|
168
|
+
| `maxOfflineDays` | `number` | `0` | Maximum days license works offline (0 = disabled) |
|
|
169
|
+
| `maxRetries` | `number` | `3` | Max retry attempts for failed API calls |
|
|
170
|
+
| `retryDelay` | `number` | `1000` | Initial retry delay in ms (exponential backoff) |
|
|
171
|
+
| `debug` | `boolean` | `false` | Enable debug logging to console |
|
|
163
172
|
|
|
164
173
|
---
|
|
165
174
|
|
|
@@ -173,17 +182,24 @@ Activates a license key on this device.
|
|
|
173
182
|
|
|
174
183
|
```javascript
|
|
175
184
|
const result = await sdk.activate('LICENSE-KEY', {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
metadata: { version: '1.0.0' }
|
|
185
|
+
deviceId: 'custom-device-id', // Optional: auto-generated if not provided
|
|
186
|
+
deviceName: "John's MacBook Pro", // Optional: human-readable device name
|
|
187
|
+
metadata: { version: '1.0.0' } // Optional: custom metadata
|
|
179
188
|
});
|
|
180
189
|
|
|
181
190
|
console.log(result);
|
|
182
191
|
// {
|
|
183
192
|
// license_key: 'LICENSE-KEY',
|
|
184
|
-
//
|
|
193
|
+
// device_id: 'web-abc123',
|
|
185
194
|
// activated_at: '2024-01-15T10:30:00Z',
|
|
186
|
-
// activation: {
|
|
195
|
+
// activation: {
|
|
196
|
+
// object: 'activation',
|
|
197
|
+
// id: 123,
|
|
198
|
+
// device_id: 'web-abc123',
|
|
199
|
+
// license_key: 'LICENSE-KEY',
|
|
200
|
+
// activated_at: '2024-01-15T10:30:00Z',
|
|
201
|
+
// license: { ... }
|
|
202
|
+
// }
|
|
187
203
|
// }
|
|
188
204
|
```
|
|
189
205
|
|
|
@@ -192,7 +208,13 @@ console.log(result);
|
|
|
192
208
|
Deactivates the current license and clears cached data.
|
|
193
209
|
|
|
194
210
|
```javascript
|
|
195
|
-
await sdk.deactivate();
|
|
211
|
+
const result = await sdk.deactivate();
|
|
212
|
+
console.log(result);
|
|
213
|
+
// {
|
|
214
|
+
// object: 'deactivation',
|
|
215
|
+
// activation_id: 123,
|
|
216
|
+
// deactivated_at: '2024-01-15T12:00:00Z'
|
|
217
|
+
// }
|
|
196
218
|
```
|
|
197
219
|
|
|
198
220
|
#### `sdk.validateLicense(licenseKey, options?)`
|
|
@@ -201,17 +223,26 @@ Validates a license with the server.
|
|
|
201
223
|
|
|
202
224
|
```javascript
|
|
203
225
|
const result = await sdk.validateLicense('LICENSE-KEY', {
|
|
204
|
-
|
|
205
|
-
productSlug: 'my-product' // Optional
|
|
226
|
+
deviceId: 'device-id' // Optional: required for hardware_locked mode
|
|
206
227
|
});
|
|
207
228
|
|
|
208
229
|
console.log(result);
|
|
209
230
|
// {
|
|
210
231
|
// valid: true,
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
//
|
|
232
|
+
// license: {
|
|
233
|
+
// key: 'LICENSE-KEY',
|
|
234
|
+
// status: 'active',
|
|
235
|
+
// mode: 'hardware_locked',
|
|
236
|
+
// plan_key: 'pro',
|
|
237
|
+
// active_seats: 1,
|
|
238
|
+
// seat_limit: 3,
|
|
239
|
+
// active_entitlements: [
|
|
240
|
+
// { key: 'pro', expires_at: null, metadata: null },
|
|
241
|
+
// { key: 'beta', expires_at: '2024-12-31T23:59:59Z', metadata: null }
|
|
242
|
+
// ],
|
|
243
|
+
// product: { slug: 'your-product', name: 'Your Product' }
|
|
244
|
+
// },
|
|
245
|
+
// active_entitlements: [...]
|
|
215
246
|
// }
|
|
216
247
|
```
|
|
217
248
|
|
|
@@ -268,7 +299,7 @@ console.log(status);
|
|
|
268
299
|
// {
|
|
269
300
|
// status: 'active',
|
|
270
301
|
// license: 'LICENSE-KEY',
|
|
271
|
-
// device: 'web-abc123
|
|
302
|
+
// device: 'web-abc123',
|
|
272
303
|
// activated_at: '2024-01-15T10:30:00Z',
|
|
273
304
|
// last_validated: '2024-01-15T11:30:00Z',
|
|
274
305
|
// entitlements: [...]
|
|
@@ -312,6 +343,7 @@ Manually initialize the SDK (only needed if `autoInitialize: false`).
|
|
|
312
343
|
```javascript
|
|
313
344
|
const sdk = new LicenseSeat({
|
|
314
345
|
apiKey: 'key',
|
|
346
|
+
productSlug: 'your-product',
|
|
315
347
|
autoInitialize: false // Don't auto-initialize
|
|
316
348
|
});
|
|
317
349
|
|
|
@@ -339,42 +371,42 @@ sdk.off('activation:success', handler);
|
|
|
339
371
|
|
|
340
372
|
### Available Events
|
|
341
373
|
|
|
342
|
-
| Event
|
|
343
|
-
|
|
344
|
-
| **Lifecycle**
|
|
345
|
-
| `license:loaded`
|
|
346
|
-
| `sdk:reset`
|
|
347
|
-
| `sdk:destroyed`
|
|
348
|
-
| `sdk:error`
|
|
349
|
-
| **Activation**
|
|
350
|
-
| `activation:start`
|
|
351
|
-
| `activation:success`
|
|
352
|
-
| `activation:error`
|
|
353
|
-
| **Deactivation**
|
|
354
|
-
| `deactivation:start`
|
|
355
|
-
| `deactivation:success`
|
|
356
|
-
| `deactivation:error`
|
|
357
|
-
| **Validation**
|
|
358
|
-
| `validation:start`
|
|
359
|
-
| `validation:success`
|
|
360
|
-
| `validation:failed`
|
|
361
|
-
| `validation:error`
|
|
362
|
-
| `validation:offline-success`
|
|
363
|
-
| `validation:offline-failed`
|
|
364
|
-
| `validation:auth-failed`
|
|
365
|
-
| **Auto-Validation**
|
|
366
|
-
| `autovalidation:cycle`
|
|
367
|
-
| `autovalidation:stopped`
|
|
368
|
-
| **Network**
|
|
369
|
-
| `network:online`
|
|
370
|
-
| `network:offline`
|
|
371
|
-
| **Offline
|
|
372
|
-
| `
|
|
373
|
-
| `
|
|
374
|
-
| `
|
|
375
|
-
| `
|
|
376
|
-
| `
|
|
377
|
-
| `
|
|
374
|
+
| Event | Description | Data |
|
|
375
|
+
| ----------------------------------- | ----------------------------------- | ------------------------------- |
|
|
376
|
+
| **Lifecycle** | | |
|
|
377
|
+
| `license:loaded` | Cached license loaded on init | `CachedLicense` |
|
|
378
|
+
| `sdk:reset` | SDK was reset | – |
|
|
379
|
+
| `sdk:destroyed` | SDK was destroyed | – |
|
|
380
|
+
| `sdk:error` | General SDK error | `{ message, error? }` |
|
|
381
|
+
| **Activation** | | |
|
|
382
|
+
| `activation:start` | Activation started | `{ licenseKey, deviceId }` |
|
|
383
|
+
| `activation:success` | Activation succeeded | `CachedLicense` |
|
|
384
|
+
| `activation:error` | Activation failed | `{ licenseKey, error }` |
|
|
385
|
+
| **Deactivation** | | |
|
|
386
|
+
| `deactivation:start` | Deactivation started | `CachedLicense` |
|
|
387
|
+
| `deactivation:success` | Deactivation succeeded | `DeactivationResponse` |
|
|
388
|
+
| `deactivation:error` | Deactivation failed | `{ error, license }` |
|
|
389
|
+
| **Validation** | | |
|
|
390
|
+
| `validation:start` | Validation started | `{ licenseKey }` |
|
|
391
|
+
| `validation:success` | Online validation succeeded | `ValidationResult` |
|
|
392
|
+
| `validation:failed` | Validation failed (invalid license) | `ValidationResult` |
|
|
393
|
+
| `validation:error` | Validation error (network, etc.) | `{ licenseKey, error }` |
|
|
394
|
+
| `validation:offline-success` | Offline validation succeeded | `ValidationResult` |
|
|
395
|
+
| `validation:offline-failed` | Offline validation failed | `ValidationResult` |
|
|
396
|
+
| `validation:auth-failed` | Auth failed during validation | `{ licenseKey, error, cached }` |
|
|
397
|
+
| **Auto-Validation** | | |
|
|
398
|
+
| `autovalidation:cycle` | Auto-validation scheduled | `{ nextRunAt: Date }` |
|
|
399
|
+
| `autovalidation:stopped` | Auto-validation stopped | – |
|
|
400
|
+
| **Network** | | |
|
|
401
|
+
| `network:online` | Network connectivity restored | – |
|
|
402
|
+
| `network:offline` | Network connectivity lost | `{ error }` |
|
|
403
|
+
| **Offline Token** | | |
|
|
404
|
+
| `offlineToken:fetching` | Fetching offline token | `{ licenseKey }` |
|
|
405
|
+
| `offlineToken:fetched` | Offline token fetched | `{ licenseKey, data }` |
|
|
406
|
+
| `offlineToken:fetchError` | Offline token fetch failed | `{ licenseKey, error }` |
|
|
407
|
+
| `offlineToken:ready` | Offline assets synced | `{ kid, exp_at }` |
|
|
408
|
+
| `offlineToken:verified` | Offline signature verified | `{ payload }` |
|
|
409
|
+
| `offlineToken:verificationFailed` | Offline signature invalid | `{ payload }` |
|
|
378
410
|
|
|
379
411
|
---
|
|
380
412
|
|
|
@@ -386,7 +418,10 @@ For applications that need a shared SDK instance:
|
|
|
386
418
|
import { configure, getSharedInstance, resetSharedInstance } from '@licenseseat/js';
|
|
387
419
|
|
|
388
420
|
// Configure once at app startup
|
|
389
|
-
configure({
|
|
421
|
+
configure({
|
|
422
|
+
apiKey: 'your-key',
|
|
423
|
+
productSlug: 'your-product'
|
|
424
|
+
});
|
|
390
425
|
|
|
391
426
|
// Use anywhere in your app
|
|
392
427
|
const sdk = getSharedInstance();
|
|
@@ -400,11 +435,12 @@ resetSharedInstance();
|
|
|
400
435
|
|
|
401
436
|
## Offline Support
|
|
402
437
|
|
|
403
|
-
The SDK supports offline license validation using cryptographically signed offline
|
|
438
|
+
The SDK supports offline license validation using cryptographically signed offline tokens (Ed25519).
|
|
404
439
|
|
|
405
440
|
```javascript
|
|
406
441
|
const sdk = new LicenseSeat({
|
|
407
442
|
apiKey: 'your-key',
|
|
443
|
+
productSlug: 'your-product',
|
|
408
444
|
offlineFallbackEnabled: true, // Enable offline fallback
|
|
409
445
|
maxOfflineDays: 7 // Allow 7 days offline
|
|
410
446
|
});
|
|
@@ -421,11 +457,45 @@ if (result.offline) {
|
|
|
421
457
|
|
|
422
458
|
### How Offline Validation Works
|
|
423
459
|
|
|
424
|
-
1. On activation, the SDK fetches a signed offline
|
|
425
|
-
2. The offline
|
|
460
|
+
1. On activation, the SDK fetches a signed offline token from the server
|
|
461
|
+
2. The offline token contains:
|
|
462
|
+
- License data (key, plan, entitlements, expiration)
|
|
463
|
+
- Ed25519 signature
|
|
464
|
+
- Canonical JSON for verification
|
|
426
465
|
3. When offline, the SDK verifies the signature locally
|
|
427
466
|
4. Clock tamper detection prevents users from bypassing expiration
|
|
428
467
|
|
|
468
|
+
### Offline Token Structure
|
|
469
|
+
|
|
470
|
+
```javascript
|
|
471
|
+
{
|
|
472
|
+
object: 'offline_token',
|
|
473
|
+
token: {
|
|
474
|
+
schema_version: 1,
|
|
475
|
+
license_key: 'LICENSE-KEY',
|
|
476
|
+
product_slug: 'your-product',
|
|
477
|
+
plan_key: 'pro',
|
|
478
|
+
mode: 'hardware_locked',
|
|
479
|
+
device_id: 'web-abc123',
|
|
480
|
+
iat: 1704067200, // Issued at (Unix timestamp)
|
|
481
|
+
exp: 1706659200, // Expires at (Unix timestamp)
|
|
482
|
+
nbf: 1704067200, // Not before (Unix timestamp)
|
|
483
|
+
license_expires_at: null,
|
|
484
|
+
kid: 'key-id-001',
|
|
485
|
+
entitlements: [
|
|
486
|
+
{ key: 'pro', expires_at: null }
|
|
487
|
+
],
|
|
488
|
+
metadata: {}
|
|
489
|
+
},
|
|
490
|
+
signature: {
|
|
491
|
+
algorithm: 'Ed25519',
|
|
492
|
+
key_id: 'key-id-001',
|
|
493
|
+
value: 'base64url-encoded-signature'
|
|
494
|
+
},
|
|
495
|
+
canonical: '{"entitlements":[...],"exp":...}'
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
429
499
|
---
|
|
430
500
|
|
|
431
501
|
## Error Handling
|
|
@@ -445,21 +515,48 @@ try {
|
|
|
445
515
|
} catch (error) {
|
|
446
516
|
if (error instanceof APIError) {
|
|
447
517
|
console.log('HTTP Status:', error.status);
|
|
448
|
-
console.log('
|
|
518
|
+
console.log('Error Code:', error.data?.error?.code);
|
|
519
|
+
console.log('Error Message:', error.data?.error?.message);
|
|
449
520
|
} else if (error instanceof LicenseError) {
|
|
450
521
|
console.log('License error:', error.code);
|
|
522
|
+
} else if (error instanceof ConfigurationError) {
|
|
523
|
+
console.log('Config error:', error.message);
|
|
451
524
|
}
|
|
452
525
|
}
|
|
453
526
|
```
|
|
454
527
|
|
|
455
528
|
### Error Types
|
|
456
529
|
|
|
457
|
-
| Error
|
|
458
|
-
|
|
459
|
-
| `APIError`
|
|
460
|
-
| `LicenseError`
|
|
461
|
-
| `ConfigurationError` | SDK misconfiguration |
|
|
462
|
-
| `CryptoError`
|
|
530
|
+
| Error | Description |
|
|
531
|
+
| -------------------- | ---------------------------------------------------- |
|
|
532
|
+
| `APIError` | HTTP request failures (includes `status` and `data`) |
|
|
533
|
+
| `LicenseError` | License operation failures (includes `code`) |
|
|
534
|
+
| `ConfigurationError` | SDK misconfiguration (e.g., missing `productSlug`) |
|
|
535
|
+
| `CryptoError` | Cryptographic operation failures |
|
|
536
|
+
|
|
537
|
+
### API Error Format
|
|
538
|
+
|
|
539
|
+
API errors follow this structure:
|
|
540
|
+
|
|
541
|
+
```javascript
|
|
542
|
+
{
|
|
543
|
+
error: {
|
|
544
|
+
code: 'license_not_found', // Machine-readable error code
|
|
545
|
+
message: 'License not found.', // Human-readable message
|
|
546
|
+
details: { ... } // Optional additional details
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
Common error codes:
|
|
552
|
+
- `unauthorized` - Invalid or missing API key
|
|
553
|
+
- `license_not_found` - License key doesn't exist
|
|
554
|
+
- `license_expired` - License has expired
|
|
555
|
+
- `license_suspended` - License is suspended
|
|
556
|
+
- `license_revoked` - License has been revoked
|
|
557
|
+
- `seat_limit_reached` - No more seats available
|
|
558
|
+
- `device_already_activated` - Device is already activated
|
|
559
|
+
- `activation_not_found` - Activation doesn't exist (for deactivation)
|
|
463
560
|
|
|
464
561
|
---
|
|
465
562
|
|
|
@@ -480,7 +577,10 @@ Simply import and use:
|
|
|
480
577
|
```javascript
|
|
481
578
|
import LicenseSeat from '@licenseseat/js';
|
|
482
579
|
|
|
483
|
-
const sdk = new LicenseSeat({
|
|
580
|
+
const sdk = new LicenseSeat({
|
|
581
|
+
apiKey: 'your-key',
|
|
582
|
+
productSlug: 'your-product'
|
|
583
|
+
});
|
|
484
584
|
```
|
|
485
585
|
|
|
486
586
|
### For TypeScript Users
|
|
@@ -491,7 +591,10 @@ The package includes TypeScript declarations (`.d.ts` files) automatically. No a
|
|
|
491
591
|
import LicenseSeat from '@licenseseat/js';
|
|
492
592
|
|
|
493
593
|
// Types are automatically available
|
|
494
|
-
const sdk = new LicenseSeat({
|
|
594
|
+
const sdk = new LicenseSeat({
|
|
595
|
+
apiKey: 'your-key',
|
|
596
|
+
productSlug: 'your-product'
|
|
597
|
+
});
|
|
495
598
|
|
|
496
599
|
// Import specific types if needed
|
|
497
600
|
import type {
|
|
@@ -500,7 +603,10 @@ import type {
|
|
|
500
603
|
EntitlementCheckResult,
|
|
501
604
|
LicenseStatus,
|
|
502
605
|
Entitlement,
|
|
503
|
-
CachedLicense
|
|
606
|
+
CachedLicense,
|
|
607
|
+
ActivationResponse,
|
|
608
|
+
DeactivationResponse,
|
|
609
|
+
OfflineToken
|
|
504
610
|
} from '@licenseseat/js';
|
|
505
611
|
```
|
|
506
612
|
|
|
@@ -520,6 +626,7 @@ Use ES modules via CDN:
|
|
|
520
626
|
|
|
521
627
|
const sdk = new LicenseSeat({
|
|
522
628
|
apiKey: 'your-api-key',
|
|
629
|
+
productSlug: 'your-product',
|
|
523
630
|
debug: true
|
|
524
631
|
});
|
|
525
632
|
|
|
@@ -561,17 +668,17 @@ npm install
|
|
|
561
668
|
|
|
562
669
|
### Scripts
|
|
563
670
|
|
|
564
|
-
| Command
|
|
565
|
-
|
|
566
|
-
| `npm run build`
|
|
567
|
-
| `npm run build:js`
|
|
568
|
-
| `npm run build:types`
|
|
569
|
-
| `npm run build:iife`
|
|
570
|
-
| `npm run dev`
|
|
571
|
-
| `npm test`
|
|
572
|
-
| `npm run test:watch`
|
|
573
|
-
| `npm run test:coverage` | Run tests with coverage report
|
|
574
|
-
| `npm run typecheck`
|
|
671
|
+
| Command | Description |
|
|
672
|
+
| ----------------------- | ----------------------------------------- |
|
|
673
|
+
| `npm run build` | Build JS bundle + TypeScript declarations |
|
|
674
|
+
| `npm run build:js` | Build JavaScript bundle only |
|
|
675
|
+
| `npm run build:types` | Generate TypeScript declarations |
|
|
676
|
+
| `npm run build:iife` | Build global/IIFE bundle |
|
|
677
|
+
| `npm run dev` | Watch mode for development |
|
|
678
|
+
| `npm test` | Run tests |
|
|
679
|
+
| `npm run test:watch` | Run tests in watch mode |
|
|
680
|
+
| `npm run test:coverage` | Run tests with coverage report |
|
|
681
|
+
| `npm run typecheck` | Type-check without emitting |
|
|
575
682
|
|
|
576
683
|
### Project Structure
|
|
577
684
|
|
|
@@ -671,17 +778,17 @@ This ensures:
|
|
|
671
778
|
|
|
672
779
|
Once published to npm, the package is automatically available on CDNs:
|
|
673
780
|
|
|
674
|
-
| CDN
|
|
675
|
-
|
|
676
|
-
| **esm.sh**
|
|
677
|
-
| **unpkg**
|
|
781
|
+
| CDN | URL |
|
|
782
|
+
| ------------ | ------------------------------------------------------------ |
|
|
783
|
+
| **esm.sh** | `https://esm.sh/@licenseseat/js` |
|
|
784
|
+
| **unpkg** | `https://unpkg.com/@licenseseat/js/dist/index.js` |
|
|
678
785
|
| **jsDelivr** | `https://cdn.jsdelivr.net/npm/@licenseseat/js/dist/index.js` |
|
|
679
|
-
| **Skypack**
|
|
786
|
+
| **Skypack** | `https://cdn.skypack.dev/@licenseseat/js` |
|
|
680
787
|
|
|
681
788
|
**Version pinning** (recommended for production):
|
|
682
789
|
```html
|
|
683
790
|
<script type="module">
|
|
684
|
-
import LicenseSeat from 'https://esm.sh/@licenseseat/js@0.
|
|
791
|
+
import LicenseSeat from 'https://esm.sh/@licenseseat/js@0.3.0';
|
|
685
792
|
</script>
|
|
686
793
|
```
|
|
687
794
|
|
|
@@ -711,7 +818,10 @@ This creates `dist/index.global.js`:
|
|
|
711
818
|
```html
|
|
712
819
|
<script src="/path/to/index.global.js"></script>
|
|
713
820
|
<script>
|
|
714
|
-
const sdk = new LicenseSeat({
|
|
821
|
+
const sdk = new LicenseSeat({
|
|
822
|
+
apiKey: 'your-key',
|
|
823
|
+
productSlug: 'your-product'
|
|
824
|
+
});
|
|
715
825
|
</script>
|
|
716
826
|
```
|
|
717
827
|
|
|
@@ -727,22 +837,80 @@ This project follows [Semantic Versioning](https://semver.org/):
|
|
|
727
837
|
|
|
728
838
|
---
|
|
729
839
|
|
|
730
|
-
## Migration from v0.
|
|
840
|
+
## Migration from v0.2.x
|
|
841
|
+
|
|
842
|
+
### Breaking Changes in v0.3.0
|
|
843
|
+
|
|
844
|
+
This version introduces the v1 API with significant changes:
|
|
845
|
+
|
|
846
|
+
| Change | Before (v0.2.x) | After (v0.3.0) |
|
|
847
|
+
| -------------------------------- | ------------------------------- | ----------------------------------------- |
|
|
848
|
+
| `productSlug` config | Not required | **Required** for all API operations |
|
|
849
|
+
| `apiBaseUrl` default | `https://licenseseat.com/api` | `https://licenseseat.com/api/v1` |
|
|
850
|
+
| `deviceIdentifier` option | `deviceIdentifier` | `deviceId` |
|
|
851
|
+
| `device_identifier` field | `device_identifier` | `device_id` |
|
|
852
|
+
| Deactivation response | Returns full activation object | Returns `{ object, activation_id, deactivated_at }` |
|
|
853
|
+
| `getOfflineLicense()` method | Available | Renamed to `getOfflineToken()` |
|
|
854
|
+
| `getPublicKey()` method | Available | Renamed to `getSigningKey()` |
|
|
855
|
+
| Offline license structure | Legacy format | New token/signature/canonical format |
|
|
856
|
+
| Error format | Various | `{ error: { code, message, details? } }` |
|
|
857
|
+
|
|
858
|
+
### Migration Steps
|
|
859
|
+
|
|
860
|
+
1. **Add `productSlug` to configuration:**
|
|
861
|
+
```javascript
|
|
862
|
+
// Before
|
|
863
|
+
const sdk = new LicenseSeat({ apiKey: 'key' });
|
|
864
|
+
|
|
865
|
+
// After
|
|
866
|
+
const sdk = new LicenseSeat({
|
|
867
|
+
apiKey: 'key',
|
|
868
|
+
productSlug: 'your-product' // Required!
|
|
869
|
+
});
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
2. **Update activation options:**
|
|
873
|
+
```javascript
|
|
874
|
+
// Before
|
|
875
|
+
await sdk.activate('KEY', { deviceIdentifier: 'id' });
|
|
876
|
+
|
|
877
|
+
// After
|
|
878
|
+
await sdk.activate('KEY', { deviceId: 'id' });
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
3. **Update response field access:**
|
|
882
|
+
```javascript
|
|
883
|
+
// Before
|
|
884
|
+
const result = await sdk.activate('KEY');
|
|
885
|
+
console.log(result.device_identifier);
|
|
886
|
+
|
|
887
|
+
// After
|
|
888
|
+
const result = await sdk.activate('KEY');
|
|
889
|
+
console.log(result.device_id);
|
|
890
|
+
```
|
|
731
891
|
|
|
732
|
-
|
|
892
|
+
4. **Update deactivation handling:**
|
|
893
|
+
```javascript
|
|
894
|
+
// Before
|
|
895
|
+
const result = await sdk.deactivate();
|
|
896
|
+
console.log(result.license_key);
|
|
733
897
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
898
|
+
// After
|
|
899
|
+
const result = await sdk.deactivate();
|
|
900
|
+
console.log(result.activation_id);
|
|
901
|
+
console.log(result.deactivated_at);
|
|
902
|
+
```
|
|
738
903
|
|
|
739
|
-
|
|
904
|
+
5. **Update offline method calls:**
|
|
905
|
+
```javascript
|
|
906
|
+
// Before
|
|
907
|
+
await sdk.getOfflineLicense(key);
|
|
908
|
+
await sdk.getPublicKey(keyId);
|
|
740
909
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
- New error classes: `LicenseError`, `ConfigurationError`, `CryptoError`
|
|
910
|
+
// After
|
|
911
|
+
await sdk.getOfflineToken(key);
|
|
912
|
+
await sdk.getSigningKey(keyId);
|
|
913
|
+
```
|
|
746
914
|
|
|
747
915
|
---
|
|
748
916
|
|
|
@@ -760,10 +928,3 @@ MIT License – see [LICENSE](LICENSE) for details.
|
|
|
760
928
|
- [GitHub Repository](https://github.com/licenseseat/licenseseat-js)
|
|
761
929
|
- [npm Package](https://www.npmjs.com/package/@licenseseat/js)
|
|
762
930
|
- [Report Issues](https://github.com/licenseseat/licenseseat-js/issues)
|
|
763
|
-
|
|
764
|
-
---
|
|
765
|
-
|
|
766
|
-
## Support
|
|
767
|
-
|
|
768
|
-
- **Email**: support@licenseseat.com
|
|
769
|
-
- **GitHub Issues**: [Report a bug](https://github.com/licenseseat/licenseseat-js/issues/new)
|