@licenseseat/js 0.3.0 → 0.3.1
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 +156 -8
- package/dist/index.global.js +2339 -0
- package/dist/index.js +17 -10
- package/dist/types/LicenseSeat.d.ts +12 -7
- package/dist/types/LicenseSeat.d.ts.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/LicenseSeat.js +19 -12
- package/src/index.js +2 -1
package/README.md
CHANGED
|
@@ -248,9 +248,11 @@ console.log(result);
|
|
|
248
248
|
|
|
249
249
|
### Entitlement Methods
|
|
250
250
|
|
|
251
|
+
> **Note:** Entitlements are optional. A license may have zero entitlements if the associated plan has no entitlements configured. The `active_entitlements` array may be empty or the field may be undefined/null.
|
|
252
|
+
|
|
251
253
|
#### `sdk.hasEntitlement(key)`
|
|
252
254
|
|
|
253
|
-
Check if an entitlement is active. Returns a simple boolean.
|
|
255
|
+
Check if an entitlement is active. Returns a simple boolean. Returns `false` if no entitlements exist.
|
|
254
256
|
|
|
255
257
|
```javascript
|
|
256
258
|
if (sdk.hasEntitlement('pro')) {
|
|
@@ -308,17 +310,21 @@ console.log(status);
|
|
|
308
310
|
|
|
309
311
|
#### `sdk.testAuth()`
|
|
310
312
|
|
|
311
|
-
Test API
|
|
313
|
+
Test API connectivity by calling the `/health` endpoint. Returns health status and API version.
|
|
312
314
|
|
|
313
315
|
```javascript
|
|
314
316
|
try {
|
|
315
317
|
const result = await sdk.testAuth();
|
|
316
|
-
console.log('Authenticated:', result.authenticated);
|
|
318
|
+
console.log('Authenticated:', result.authenticated); // Always true if request succeeds
|
|
319
|
+
console.log('Healthy:', result.healthy); // API health status
|
|
320
|
+
console.log('API Version:', result.api_version); // e.g., '1.0.0'
|
|
317
321
|
} catch (error) {
|
|
318
|
-
console.error('
|
|
322
|
+
console.error('Connection failed:', error);
|
|
319
323
|
}
|
|
320
324
|
```
|
|
321
325
|
|
|
326
|
+
> **Note:** This method tests API connectivity, not API key validity. A successful response means the API is reachable. Authentication errors will surface when calling protected endpoints like `activate()` or `validateLicense()`.
|
|
327
|
+
|
|
322
328
|
#### `sdk.reset()`
|
|
323
329
|
|
|
324
330
|
Clear all cached data and reset SDK state.
|
|
@@ -465,6 +471,70 @@ if (result.offline) {
|
|
|
465
471
|
3. When offline, the SDK verifies the signature locally
|
|
466
472
|
4. Clock tamper detection prevents users from bypassing expiration
|
|
467
473
|
|
|
474
|
+
### Offline Methods
|
|
475
|
+
|
|
476
|
+
#### `sdk.syncOfflineAssets()`
|
|
477
|
+
|
|
478
|
+
Fetches the offline token and signing key from the server. Uses the currently cached license. Call this after activation to prepare for offline usage.
|
|
479
|
+
|
|
480
|
+
```javascript
|
|
481
|
+
// First activate (caches the license)
|
|
482
|
+
await sdk.activate('LICENSE-KEY');
|
|
483
|
+
|
|
484
|
+
// Then sync offline assets (uses cached license)
|
|
485
|
+
const assets = await sdk.syncOfflineAssets();
|
|
486
|
+
console.log('Offline token key ID:', assets.kid);
|
|
487
|
+
console.log('Expires at:', assets.exp_at);
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
#### `sdk.getOfflineToken()`
|
|
491
|
+
|
|
492
|
+
Fetches a signed offline token for the currently cached license. Returns the token structure containing the license data and Ed25519 signature.
|
|
493
|
+
|
|
494
|
+
```javascript
|
|
495
|
+
// Must have an active license cached first
|
|
496
|
+
const token = await sdk.getOfflineToken();
|
|
497
|
+
console.log(token);
|
|
498
|
+
// {
|
|
499
|
+
// object: 'offline_token',
|
|
500
|
+
// token: { license_key, product_slug, plan_key, ... },
|
|
501
|
+
// signature: { algorithm: 'Ed25519', key_id, value },
|
|
502
|
+
// canonical: '...'
|
|
503
|
+
// }
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
#### `sdk.getSigningKey(keyId)`
|
|
507
|
+
|
|
508
|
+
Fetches the Ed25519 public key used for verifying offline token signatures.
|
|
509
|
+
|
|
510
|
+
```javascript
|
|
511
|
+
const signingKey = await sdk.getSigningKey('key-id-001');
|
|
512
|
+
console.log(signingKey);
|
|
513
|
+
// {
|
|
514
|
+
// object: 'signing_key',
|
|
515
|
+
// kid: 'key-id-001',
|
|
516
|
+
// public_key: 'base64-encoded-public-key',
|
|
517
|
+
// algorithm: 'Ed25519',
|
|
518
|
+
// created_at: '2024-01-01T00:00:00Z'
|
|
519
|
+
// }
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
#### `sdk.verifyOfflineToken(token, publicKeyB64)`
|
|
523
|
+
|
|
524
|
+
Verifies an offline token's Ed25519 signature locally. **Both parameters are required.**
|
|
525
|
+
|
|
526
|
+
```javascript
|
|
527
|
+
// Fetch the token and signing key first
|
|
528
|
+
const token = await sdk.getOfflineToken();
|
|
529
|
+
const signingKey = await sdk.getSigningKey(token.signature.key_id);
|
|
530
|
+
|
|
531
|
+
// Verify the signature
|
|
532
|
+
const isValid = await sdk.verifyOfflineToken(token, signingKey.public_key);
|
|
533
|
+
console.log('Signature valid:', isValid);
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
> **Important:** The `verifyOfflineToken()` method requires you to pass both the token and the public key. Fetch the signing key using `getSigningKey()` with the `key_id` from the token's signature.
|
|
537
|
+
|
|
468
538
|
### Offline Token Structure
|
|
469
539
|
|
|
470
540
|
```javascript
|
|
@@ -564,7 +634,39 @@ Common error codes:
|
|
|
564
634
|
|
|
565
635
|
- **Modern browsers**: Chrome 80+, Firefox 75+, Safari 14+, Edge 80+
|
|
566
636
|
- **Bundlers**: Vite, Webpack, Rollup, esbuild, Parcel
|
|
567
|
-
- **Node.js**: 18+ (requires polyfills
|
|
637
|
+
- **Node.js**: 18+ (requires polyfills - see below)
|
|
638
|
+
|
|
639
|
+
### Node.js Usage
|
|
640
|
+
|
|
641
|
+
The SDK is designed for browsers but works in Node.js with polyfills. Add these before importing the SDK:
|
|
642
|
+
|
|
643
|
+
```javascript
|
|
644
|
+
// Required polyfills for Node.js
|
|
645
|
+
const storage = {};
|
|
646
|
+
globalThis.localStorage = {
|
|
647
|
+
getItem(key) { return Object.prototype.hasOwnProperty.call(storage, key) ? storage[key] : null; },
|
|
648
|
+
setItem(key, value) { storage[key] = String(value); },
|
|
649
|
+
removeItem(key) { delete storage[key]; },
|
|
650
|
+
clear() { for (const key in storage) delete storage[key]; },
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
// Override Object.keys to support localStorage iteration (used by cache.getAllKeys())
|
|
654
|
+
const originalKeys = Object.keys;
|
|
655
|
+
Object.keys = function(obj) {
|
|
656
|
+
if (obj === globalThis.localStorage) return originalKeys(storage);
|
|
657
|
+
return originalKeys(obj);
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
// Device fingerprinting polyfills (provides stable fallback values)
|
|
661
|
+
globalThis.document = { createElement: () => ({ getContext: () => null }), querySelector: () => null };
|
|
662
|
+
globalThis.window = { navigator: {}, screen: {} };
|
|
663
|
+
globalThis.navigator = { userAgent: 'Node.js', language: 'en', hardwareConcurrency: 4 };
|
|
664
|
+
|
|
665
|
+
// Now import the SDK
|
|
666
|
+
const { default: LicenseSeat } = await import('@licenseseat/js');
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
> **Note:** In Node.js, device fingerprinting will use fallback values since browser APIs aren't available. For consistent device identification across restarts, pass an explicit `deviceId` to `activate()`.
|
|
568
670
|
|
|
569
671
|
---
|
|
570
672
|
|
|
@@ -680,6 +782,50 @@ npm install
|
|
|
680
782
|
| `npm run test:coverage` | Run tests with coverage report |
|
|
681
783
|
| `npm run typecheck` | Type-check without emitting |
|
|
682
784
|
|
|
785
|
+
### Integration Tests
|
|
786
|
+
|
|
787
|
+
The SDK includes comprehensive integration tests that run against the live LicenseSeat API. These tests verify real-world functionality including activation, validation, deactivation, and offline cryptographic operations.
|
|
788
|
+
|
|
789
|
+
#### Running Integration Tests (Node.js)
|
|
790
|
+
|
|
791
|
+
```bash
|
|
792
|
+
# Set environment variables
|
|
793
|
+
export LICENSESEAT_API_KEY="ls_your_api_key_here"
|
|
794
|
+
export LICENSESEAT_PRODUCT_SLUG="your-product"
|
|
795
|
+
export LICENSESEAT_LICENSE_KEY="YOUR-LICENSE-KEY"
|
|
796
|
+
|
|
797
|
+
# Run the tests
|
|
798
|
+
node test-live.mjs
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
Or with inline environment variables:
|
|
802
|
+
|
|
803
|
+
```bash
|
|
804
|
+
LICENSESEAT_API_KEY=ls_xxx LICENSESEAT_PRODUCT_SLUG=my-app LICENSESEAT_LICENSE_KEY=XXX-XXX node test-live.mjs
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
#### Running Integration Tests (Browser)
|
|
808
|
+
|
|
809
|
+
Open `test-live.html` in a browser. You'll be prompted to enter your credentials:
|
|
810
|
+
|
|
811
|
+
1. **API Key** - Your LicenseSeat API key (starts with `ls_`)
|
|
812
|
+
2. **Product Slug** - Your product identifier
|
|
813
|
+
3. **License Key** - A valid license key for testing
|
|
814
|
+
|
|
815
|
+
Credentials are stored in `localStorage` for convenience during development.
|
|
816
|
+
|
|
817
|
+
#### What the Integration Tests Cover
|
|
818
|
+
|
|
819
|
+
| Category | Tests |
|
|
820
|
+
|----------|-------|
|
|
821
|
+
| **Initialization** | SDK setup, configuration defaults |
|
|
822
|
+
| **Activation** | License activation, device ID generation |
|
|
823
|
+
| **Validation** | Online validation, entitlement checking |
|
|
824
|
+
| **Deactivation** | License deactivation, cache clearing |
|
|
825
|
+
| **Offline Crypto** | Ed25519 signature verification, offline token fetching, tamper detection |
|
|
826
|
+
| **Error Handling** | Invalid licenses, missing config |
|
|
827
|
+
| **Singleton** | Shared instance pattern |
|
|
828
|
+
|
|
683
829
|
### Project Structure
|
|
684
830
|
|
|
685
831
|
```
|
|
@@ -691,11 +837,13 @@ licenseseat-js/
|
|
|
691
837
|
│ ├── errors.js # Error classes
|
|
692
838
|
│ ├── types.js # JSDoc type definitions
|
|
693
839
|
│ └── utils.js # Utility functions
|
|
694
|
-
├── tests/
|
|
840
|
+
├── tests/ # Unit tests (mocked API)
|
|
695
841
|
│ ├── setup.js # Test setup
|
|
696
842
|
│ ├── mocks/ # MSW handlers
|
|
697
843
|
│ ├── LicenseSeat.test.js
|
|
698
844
|
│ └── utils.test.js
|
|
845
|
+
├── test-live.mjs # Integration tests (Node.js)
|
|
846
|
+
├── test-live.html # Integration tests (Browser)
|
|
699
847
|
├── dist/ # Build output
|
|
700
848
|
│ ├── index.js # ESM bundle
|
|
701
849
|
│ └── types/ # TypeScript declarations
|
|
@@ -907,8 +1055,8 @@ This version introduces the v1 API with significant changes:
|
|
|
907
1055
|
await sdk.getOfflineLicense(key);
|
|
908
1056
|
await sdk.getPublicKey(keyId);
|
|
909
1057
|
|
|
910
|
-
// After
|
|
911
|
-
await sdk.getOfflineToken(
|
|
1058
|
+
// After (note: getOfflineToken uses cached license, no parameter needed)
|
|
1059
|
+
await sdk.getOfflineToken();
|
|
912
1060
|
await sdk.getSigningKey(keyId);
|
|
913
1061
|
```
|
|
914
1062
|
|