@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/src/cache.js CHANGED
@@ -62,12 +62,12 @@ export class LicenseCache {
62
62
  }
63
63
 
64
64
  /**
65
- * Get the device identifier from the cached license
66
- * @returns {string|null} Device identifier or null if not found
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.device_identifier : null;
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 license
83
- * @returns {import('./types.js').SignedOfflineLicense|null} Offline license or null if not found
82
+ * Get the cached offline token
83
+ * @returns {import('./types.js').OfflineToken|null} Offline token or null if not found
84
84
  */
85
- getOfflineLicense() {
85
+ getOfflineToken() {
86
86
  try {
87
- const data = localStorage.getItem(this.prefix + "offline_license");
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 license cache:", e);
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 license data in cache
97
- * @param {import('./types.js').SignedOfflineLicense} data - Signed offline license to cache
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
- setOfflineLicense(data) {
100
+ setOfflineToken(data) {
101
101
  try {
102
102
  localStorage.setItem(
103
- this.prefix + "offline_license",
103
+ this.prefix + "offline_token",
104
104
  JSON.stringify(data)
105
105
  );
106
106
  } catch (e) {
107
- console.error("Failed to cache offline license:", e);
107
+ console.error("Failed to cache offline token:", e);
108
108
  }
109
109
  }
110
110
 
111
111
  /**
112
- * Clear the cached offline license
112
+ * Clear the cached offline token
113
113
  * @returns {void}
114
114
  */
115
- clearOfflineLicense() {
116
- localStorage.removeItem(this.prefix + "offline_license");
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 license (default: 72 hours)
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} [deviceIdentifier] - Custom device identifier (auto-generated if not provided)
29
- * @property {string} [softwareReleaseDate] - ISO8601 date string for version-aware activation
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} [deviceIdentifier] - Device identifier to validate against
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} id - Activation ID
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} device_identifier - Device identifier
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} [reason] - Reason for invalid status (online)
76
- * @property {string} [reason_code] - Machine-readable reason code (offline)
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 identifier (if active)
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 license payload
104
- * @typedef {Object} OfflineLicensePayload
105
- * @property {number} [v] - Payload version (currently 1)
106
- * @property {string} [lic_k] - License key
107
- * @property {string} [prod_s] - Product slug
108
- * @property {string} [plan_k] - License plan key
109
- * @property {string|null} [exp_at] - ISO8601 expiration timestamp (null for perpetual)
110
- * @property {number|null} [sl] - Seat limit (null for unlimited)
111
- * @property {string} [kid] - Key ID for public key lookup
112
- * @property {Array<{key: string, expires_at: string|null, metadata: Object|null}>} [active_ents] - Active entitlements
113
- * @property {Array<{key: string, expires_at: string|null, metadata: Object|null}>} [active_entitlements] - Active entitlements (alternative key)
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
- * Signed offline license data
119
- * @typedef {Object} SignedOfflineLicense
120
- * @property {OfflineLicensePayload} payload - The license payload
121
- * @property {string} signature_b64u - Base64URL-encoded Ed25519 signature
122
- * @property {string} [kid] - Key ID for public key lookup
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 {string} [error] - Error message
142
- * @property {string} [reason_code] - Machine-readable reason code (e.g., "license_not_found", "expired", "revoked")
143
- * @property {string} [code] - Legacy error code (deprecated, use reason_code)
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 license
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
- const raw = payload.active_ents || payload.active_entitlements || [];
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,