@licenseseat/js 0.2.2 → 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 +227 -66
- package/dist/index.js +181 -138
- package/dist/types/LicenseSeat.d.ts +22 -12
- 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 +1 -1
- package/dist/types/utils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/LicenseSeat.js +188 -138
- package/src/cache.js +16 -18
- package/src/types.js +126 -34
- package/src/utils.js +3 -2
package/src/cache.js
CHANGED
|
@@ -62,12 +62,12 @@ export class LicenseCache {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* Get the device
|
|
66
|
-
* @returns {string|null} Device
|
|
65
|
+
* Get the device ID from the cached license
|
|
66
|
+
* @returns {string|null} Device ID or null if not found
|
|
67
67
|
*/
|
|
68
68
|
getDeviceId() {
|
|
69
69
|
const license = this.getLicense();
|
|
70
|
-
return license ? license.
|
|
70
|
+
return license ? license.device_id : null;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
@@ -79,41 +79,41 @@ export class LicenseCache {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
* Get the cached offline
|
|
83
|
-
* @returns {import('./types.js').
|
|
82
|
+
* Get the cached offline token
|
|
83
|
+
* @returns {import('./types.js').OfflineToken|null} Offline token or null if not found
|
|
84
84
|
*/
|
|
85
|
-
|
|
85
|
+
getOfflineToken() {
|
|
86
86
|
try {
|
|
87
|
-
const data = localStorage.getItem(this.prefix + "
|
|
87
|
+
const data = localStorage.getItem(this.prefix + "offline_token");
|
|
88
88
|
return data ? JSON.parse(data) : null;
|
|
89
89
|
} catch (e) {
|
|
90
|
-
console.error("Failed to read offline
|
|
90
|
+
console.error("Failed to read offline token cache:", e);
|
|
91
91
|
return null;
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
|
-
* Store offline
|
|
97
|
-
* @param {import('./types.js').
|
|
96
|
+
* Store offline token data in cache
|
|
97
|
+
* @param {import('./types.js').OfflineToken} data - Offline token to cache
|
|
98
98
|
* @returns {void}
|
|
99
99
|
*/
|
|
100
|
-
|
|
100
|
+
setOfflineToken(data) {
|
|
101
101
|
try {
|
|
102
102
|
localStorage.setItem(
|
|
103
|
-
this.prefix + "
|
|
103
|
+
this.prefix + "offline_token",
|
|
104
104
|
JSON.stringify(data)
|
|
105
105
|
);
|
|
106
106
|
} catch (e) {
|
|
107
|
-
console.error("Failed to cache offline
|
|
107
|
+
console.error("Failed to cache offline token:", e);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
|
-
* Clear the cached offline
|
|
112
|
+
* Clear the cached offline token
|
|
113
113
|
* @returns {void}
|
|
114
114
|
*/
|
|
115
|
-
|
|
116
|
-
localStorage.removeItem(this.prefix + "
|
|
115
|
+
clearOfflineToken() {
|
|
116
|
+
localStorage.removeItem(this.prefix + "offline_token");
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
/**
|
|
@@ -161,8 +161,6 @@ export class LicenseCache {
|
|
|
161
161
|
localStorage.removeItem(key);
|
|
162
162
|
}
|
|
163
163
|
});
|
|
164
|
-
this.clearOfflineLicense();
|
|
165
|
-
localStorage.removeItem(this.prefix + "last_seen_ts");
|
|
166
164
|
}
|
|
167
165
|
|
|
168
166
|
/**
|
package/src/types.js
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
/**
|
|
8
8
|
* SDK Configuration options
|
|
9
9
|
* @typedef {Object} LicenseSeatConfig
|
|
10
|
-
* @property {string} [apiBaseUrl="https://licenseseat.com/api"] - Base URL for the LicenseSeat API
|
|
10
|
+
* @property {string} [apiBaseUrl="https://licenseseat.com/api/v1"] - Base URL for the LicenseSeat API
|
|
11
|
+
* @property {string} [productSlug] - Product slug (required for API calls, e.g., "my-app")
|
|
11
12
|
* @property {string} [apiKey] - API key for authentication (required for most operations)
|
|
12
13
|
* @property {string} [storagePrefix="licenseseat_"] - Prefix for localStorage keys
|
|
13
14
|
* @property {number} [autoValidateInterval=3600000] - Interval in ms for automatic license validation (default: 1 hour)
|
|
@@ -15,7 +16,7 @@
|
|
|
15
16
|
* @property {number} [maxRetries=3] - Maximum number of retry attempts for failed API calls
|
|
16
17
|
* @property {number} [retryDelay=1000] - Initial delay in ms between retries (exponential backoff applied)
|
|
17
18
|
* @property {boolean} [debug=false] - Enable debug logging to console
|
|
18
|
-
* @property {number} [offlineLicenseRefreshInterval=259200000] - Interval in ms to refresh offline
|
|
19
|
+
* @property {number} [offlineLicenseRefreshInterval=259200000] - Interval in ms to refresh offline token (default: 72 hours)
|
|
19
20
|
* @property {boolean} [offlineFallbackEnabled=false] - Enable offline validation fallback on network errors
|
|
20
21
|
* @property {number} [maxOfflineDays=0] - Maximum days a license can be used offline (0 = disabled)
|
|
21
22
|
* @property {number} [maxClockSkewMs=300000] - Maximum allowed clock skew in ms for offline validation (default: 5 minutes)
|
|
@@ -25,33 +26,68 @@
|
|
|
25
26
|
/**
|
|
26
27
|
* License activation options
|
|
27
28
|
* @typedef {Object} ActivationOptions
|
|
28
|
-
* @property {string} [
|
|
29
|
-
* @property {string} [
|
|
29
|
+
* @property {string} [deviceId] - Custom device ID (auto-generated if not provided)
|
|
30
|
+
* @property {string} [deviceName] - Human-readable device name (e.g., "John's MacBook Pro")
|
|
30
31
|
* @property {Object} [metadata] - Additional metadata to include with the activation
|
|
31
32
|
*/
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* License validation options
|
|
35
36
|
* @typedef {Object} ValidationOptions
|
|
36
|
-
* @property {string} [
|
|
37
|
-
* @property {string} [productSlug] - Product slug for product-specific validation
|
|
37
|
+
* @property {string} [deviceId] - Device ID to validate against (required for hardware_locked mode)
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Activation response from the API
|
|
42
42
|
* @typedef {Object} ActivationResponse
|
|
43
|
-
* @property {string}
|
|
43
|
+
* @property {string} object - Object type ("activation")
|
|
44
|
+
* @property {number} id - Activation ID
|
|
45
|
+
* @property {string} device_id - Device ID used for activation
|
|
46
|
+
* @property {string} [device_name] - Human-readable device name
|
|
44
47
|
* @property {string} license_key - The activated license key
|
|
45
|
-
* @property {string} device_identifier - Device identifier used for activation
|
|
46
48
|
* @property {string} activated_at - ISO8601 timestamp of activation
|
|
49
|
+
* @property {string|null} [deactivated_at] - ISO8601 timestamp of deactivation (null if active)
|
|
50
|
+
* @property {string} [ip_address] - IP address of activation request
|
|
47
51
|
* @property {Object} [metadata] - Additional metadata
|
|
52
|
+
* @property {LicenseObject} license - The license object
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Deactivation response from the API
|
|
57
|
+
* @typedef {Object} DeactivationResponse
|
|
58
|
+
* @property {string} object - Object type ("deactivation")
|
|
59
|
+
* @property {number} activation_id - The deactivated activation ID
|
|
60
|
+
* @property {string} deactivated_at - ISO8601 timestamp of deactivation
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* License object from API responses
|
|
65
|
+
* @typedef {Object} LicenseObject
|
|
66
|
+
* @property {string} key - The license key
|
|
67
|
+
* @property {string} status - License status ("active", "revoked", "suspended", etc.)
|
|
68
|
+
* @property {string} [starts_at] - ISO8601 start timestamp
|
|
69
|
+
* @property {string|null} [expires_at] - ISO8601 expiration timestamp (null for perpetual)
|
|
70
|
+
* @property {string} mode - License mode ("hardware_locked", "floating", "named_user")
|
|
71
|
+
* @property {string} plan_key - License plan key
|
|
72
|
+
* @property {number} [seat_limit] - Maximum allowed seats
|
|
73
|
+
* @property {number} active_seats - Currently active seats
|
|
74
|
+
* @property {Entitlement[]} active_entitlements - List of active entitlements
|
|
75
|
+
* @property {Object} [metadata] - Additional metadata
|
|
76
|
+
* @property {ProductInfo} product - Product information
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Product information
|
|
81
|
+
* @typedef {Object} ProductInfo
|
|
82
|
+
* @property {string} slug - Product slug
|
|
83
|
+
* @property {string} name - Product display name
|
|
48
84
|
*/
|
|
49
85
|
|
|
50
86
|
/**
|
|
51
87
|
* Cached license data
|
|
52
88
|
* @typedef {Object} CachedLicense
|
|
53
89
|
* @property {string} license_key - The license key
|
|
54
|
-
* @property {string}
|
|
90
|
+
* @property {string} device_id - Device ID
|
|
55
91
|
* @property {ActivationResponse} [activation] - Original activation response
|
|
56
92
|
* @property {string} activated_at - ISO8601 timestamp of activation
|
|
57
93
|
* @property {string} last_validated - ISO8601 timestamp of last validation
|
|
@@ -60,10 +96,9 @@
|
|
|
60
96
|
|
|
61
97
|
/**
|
|
62
98
|
* Entitlement object
|
|
63
|
-
* Note: API returns only key, expires_at, and metadata. Name/description are not provided.
|
|
64
99
|
* @typedef {Object} Entitlement
|
|
65
100
|
* @property {string} key - Unique entitlement key
|
|
66
|
-
* @property {string|null} expires_at - ISO8601 expiration timestamp
|
|
101
|
+
* @property {string|null} expires_at - ISO8601 expiration timestamp (null for perpetual)
|
|
67
102
|
* @property {Object|null} metadata - Additional metadata
|
|
68
103
|
*/
|
|
69
104
|
|
|
@@ -72,12 +107,22 @@
|
|
|
72
107
|
* @typedef {Object} ValidationResult
|
|
73
108
|
* @property {boolean} valid - Whether the license is valid
|
|
74
109
|
* @property {boolean} [offline] - Whether this was an offline validation
|
|
75
|
-
* @property {string} [
|
|
76
|
-
* @property {string} [
|
|
110
|
+
* @property {string} [code] - Machine-readable reason code (when invalid)
|
|
111
|
+
* @property {string} [message] - Human-readable message (when invalid)
|
|
112
|
+
* @property {ValidationWarning[]} [warnings] - Non-fatal warnings (e.g., expiring soon)
|
|
113
|
+
* @property {LicenseObject} [license] - The license object (online validation)
|
|
114
|
+
* @property {ActivationResponse} [activation] - The activation object (if device_id provided)
|
|
77
115
|
* @property {Entitlement[]} [active_entitlements] - List of active entitlements
|
|
78
116
|
* @property {boolean} [optimistic] - Whether this is an optimistic validation (pending server confirmation)
|
|
79
117
|
*/
|
|
80
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Validation warning
|
|
121
|
+
* @typedef {Object} ValidationWarning
|
|
122
|
+
* @property {string} code - Warning code (e.g., "license_expiring_soon")
|
|
123
|
+
* @property {string} message - Human-readable warning message
|
|
124
|
+
*/
|
|
125
|
+
|
|
81
126
|
/**
|
|
82
127
|
* Entitlement check result
|
|
83
128
|
* @typedef {Object} EntitlementCheckResult
|
|
@@ -93,33 +138,73 @@
|
|
|
93
138
|
* @property {string} status - Status string ("inactive" | "pending" | "invalid" | "offline-invalid" | "offline-valid" | "active")
|
|
94
139
|
* @property {string} [message] - Human-readable status message
|
|
95
140
|
* @property {string} [license] - License key (if active)
|
|
96
|
-
* @property {string} [device] - Device
|
|
141
|
+
* @property {string} [device] - Device ID (if active)
|
|
97
142
|
* @property {string} [activated_at] - ISO8601 activation timestamp
|
|
98
143
|
* @property {string} [last_validated] - ISO8601 last validation timestamp
|
|
99
144
|
* @property {Entitlement[]} [entitlements] - List of active entitlements
|
|
100
145
|
*/
|
|
101
146
|
|
|
102
147
|
/**
|
|
103
|
-
* Offline
|
|
104
|
-
* @typedef {Object}
|
|
105
|
-
* @property {
|
|
106
|
-
* @property {
|
|
107
|
-
* @property {
|
|
108
|
-
* @property {string}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
*
|
|
113
|
-
* @
|
|
148
|
+
* Offline token data (new v1 format)
|
|
149
|
+
* @typedef {Object} OfflineToken
|
|
150
|
+
* @property {string} object - Object type ("offline_token")
|
|
151
|
+
* @property {OfflineTokenPayload} token - The token payload
|
|
152
|
+
* @property {OfflineTokenSignature} signature - Signature information
|
|
153
|
+
* @property {string} canonical - Canonical JSON string that was signed
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Offline token payload
|
|
158
|
+
* @typedef {Object} OfflineTokenPayload
|
|
159
|
+
* @property {number} schema_version - Token schema version (currently 1)
|
|
160
|
+
* @property {string} license_key - License key
|
|
161
|
+
* @property {string} product_slug - Product slug
|
|
162
|
+
* @property {string} plan_key - License plan key
|
|
163
|
+
* @property {string} mode - License mode ("hardware_locked", "floating", "named_user")
|
|
164
|
+
* @property {number|null} [seat_limit] - Seat limit (null for unlimited)
|
|
165
|
+
* @property {string|null} [device_id] - Device ID (required for hardware_locked mode)
|
|
166
|
+
* @property {number} iat - Issued at (Unix timestamp in seconds)
|
|
167
|
+
* @property {number} exp - Expires at (Unix timestamp in seconds)
|
|
168
|
+
* @property {number} nbf - Not before (Unix timestamp in seconds)
|
|
169
|
+
* @property {number|null} [license_expires_at] - License expiration (Unix timestamp in seconds, null for perpetual)
|
|
170
|
+
* @property {string} kid - Key ID for signature verification
|
|
171
|
+
* @property {OfflineEntitlement[]} entitlements - Active entitlements
|
|
114
172
|
* @property {Object} [metadata] - Additional metadata
|
|
115
173
|
*/
|
|
116
174
|
|
|
117
175
|
/**
|
|
118
|
-
*
|
|
119
|
-
* @typedef {Object}
|
|
120
|
-
* @property {
|
|
121
|
-
* @property {
|
|
122
|
-
|
|
176
|
+
* Offline token entitlement
|
|
177
|
+
* @typedef {Object} OfflineEntitlement
|
|
178
|
+
* @property {string} key - Entitlement key
|
|
179
|
+
* @property {number|null} [expires_at] - Expiration (Unix timestamp in seconds)
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Offline token signature
|
|
184
|
+
* @typedef {Object} OfflineTokenSignature
|
|
185
|
+
* @property {string} algorithm - Signature algorithm (e.g., "Ed25519")
|
|
186
|
+
* @property {string} key_id - Key ID for public key lookup
|
|
187
|
+
* @property {string} value - Base64URL-encoded signature value
|
|
188
|
+
*/
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Signing key response from API
|
|
192
|
+
* @typedef {Object} SigningKey
|
|
193
|
+
* @property {string} object - Object type ("signing_key")
|
|
194
|
+
* @property {string} key_id - Key ID
|
|
195
|
+
* @property {string} algorithm - Algorithm (e.g., "Ed25519")
|
|
196
|
+
* @property {string} public_key - Base64-encoded public key
|
|
197
|
+
* @property {string} [created_at] - ISO8601 creation timestamp
|
|
198
|
+
* @property {string} status - Key status ("active", "revoked")
|
|
199
|
+
*/
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Health check response
|
|
203
|
+
* @typedef {Object} HealthResponse
|
|
204
|
+
* @property {string} object - Object type ("health")
|
|
205
|
+
* @property {string} status - Health status ("healthy")
|
|
206
|
+
* @property {string} api_version - API version string
|
|
207
|
+
* @property {string} timestamp - ISO8601 timestamp
|
|
123
208
|
*/
|
|
124
209
|
|
|
125
210
|
/**
|
|
@@ -136,11 +221,18 @@
|
|
|
136
221
|
*/
|
|
137
222
|
|
|
138
223
|
/**
|
|
139
|
-
* API Error data
|
|
224
|
+
* API Error data (new format)
|
|
140
225
|
* @typedef {Object} APIErrorData
|
|
141
|
-
* @property {
|
|
142
|
-
* @property {string} [
|
|
143
|
-
* @property {string} [
|
|
226
|
+
* @property {APIErrorObject} [error] - Error object (new format)
|
|
227
|
+
* @property {string} [code] - Machine-readable error code (fallback)
|
|
228
|
+
* @property {string} [message] - Human-readable error message (fallback)
|
|
229
|
+
*/
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* API Error object
|
|
233
|
+
* @typedef {Object} APIErrorObject
|
|
234
|
+
* @property {string} code - Machine-readable error code
|
|
235
|
+
* @property {string} message - Human-readable error message
|
|
144
236
|
* @property {Object} [details] - Additional error details
|
|
145
237
|
*/
|
|
146
238
|
|
package/src/utils.js
CHANGED
|
@@ -8,11 +8,12 @@ import CJSON from "canonical-json";
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Parse active entitlements from a raw API payload into a consistent shape
|
|
11
|
-
* @param {Object} [payload={}] - Raw payload from API or offline
|
|
11
|
+
* @param {Object} [payload={}] - Raw payload from API or offline token
|
|
12
12
|
* @returns {import('./types.js').Entitlement[]} Normalized entitlements array
|
|
13
13
|
*/
|
|
14
14
|
export function parseActiveEntitlements(payload = {}) {
|
|
15
|
-
|
|
15
|
+
// New v1 API uses "entitlements" or "active_entitlements"
|
|
16
|
+
const raw = payload.entitlements || payload.active_entitlements || [];
|
|
16
17
|
return raw.map((e) => ({
|
|
17
18
|
key: e.key,
|
|
18
19
|
expires_at: e.expires_at ?? null,
|