@gorilla-engine-sdk/ge-product-hub 0.1.4
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/License.md +64 -0
- package/README.md +202 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -0
- package/dist/lib/clients.d.ts +1039 -0
- package/dist/lib/clients.js +2036 -0
- package/dist/lib/credentialStore.d.ts +8 -0
- package/dist/lib/credentialStore.js +80 -0
- package/dist/lib/errors.d.ts +48 -0
- package/dist/lib/errors.js +63 -0
- package/dist/lib/types.d.ts +406 -0
- package/dist/lib/types.js +58 -0
- package/package.json +48 -0
|
@@ -0,0 +1,1039 @@
|
|
|
1
|
+
import { ActivateProductParams, ActivateProductResponse, ActivationRestoreResult, StoredSessionActivationResult, ActivateTrialResponse, APIClientOptions, AudioPluginClientOptions, AudioPluginActivationParams, AudioPluginActivationWithSerialParams, AudioPluginClaimAndActivateParams, AudioPluginStoredSessionSerialParams, ActivationStatus, StoredSessionInfo, OfflineActivationFileOptions, LicenseType, LatestProductVersionResponse, BuildFile } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
* Fixed signature seed version used for cryptographic verification.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SIGNATURE_SEED_VERSION = 6;
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
* Hardware fingerprint version for system identification.
|
|
10
|
+
*/
|
|
11
|
+
export declare const HARDWARE_FINGERPRINT_VERSION = 2;
|
|
12
|
+
/**
|
|
13
|
+
* Gorilla Engine Product Hub Client Library
|
|
14
|
+
*
|
|
15
|
+
* Provides comprehensive audio plugin licensing with
|
|
16
|
+
* activation management & trial handling.
|
|
17
|
+
*/
|
|
18
|
+
export declare namespace ProductHub {
|
|
19
|
+
/**
|
|
20
|
+
* @internal
|
|
21
|
+
* Low-level API client for Product Hub communication.
|
|
22
|
+
* This class is used internally and should not be used directly.
|
|
23
|
+
* Use AudioPluginClient instead for a complete audio plugin licensing solution.
|
|
24
|
+
*/
|
|
25
|
+
class APIClient {
|
|
26
|
+
private manufacturerId;
|
|
27
|
+
private productId;
|
|
28
|
+
private hwfpUtil;
|
|
29
|
+
private bearerToken;
|
|
30
|
+
/**
|
|
31
|
+
* Create a low-level Product Hub API client.
|
|
32
|
+
*
|
|
33
|
+
* @param options - Product, manufacturer, and optional fingerprint settings.
|
|
34
|
+
* @throws {@link ProductHubError} If a required identifier is missing, the runtime is older
|
|
35
|
+
* than Node.js 18.3, global `fetch` is unavailable, or fingerprint generation fails.
|
|
36
|
+
* @remarks One stored login session is shared by all products from this manufacturer.
|
|
37
|
+
* `hardwareFingerprint` is intended for tests; production clients should use the Gorilla
|
|
38
|
+
* Engine hardware-fingerprinting binding.
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const apiClient = new ProductHub.APIClient({
|
|
42
|
+
* manufacturerId: 'manufacturer-id',
|
|
43
|
+
* productId: 'product-id',
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
constructor(options: APIClientOptions);
|
|
48
|
+
private credentialLocation;
|
|
49
|
+
private isTokenUsable;
|
|
50
|
+
private readPersistedToken;
|
|
51
|
+
private loadPersistedToken;
|
|
52
|
+
private persistToken;
|
|
53
|
+
/**
|
|
54
|
+
* Check whether a usable login session is stored for this product and device.
|
|
55
|
+
*
|
|
56
|
+
* @returns A promise resolving to `true` when a usable session exists; otherwise `false`.
|
|
57
|
+
* @remarks Malformed, expired, or wrong-scope stored tokens are removed before returning.
|
|
58
|
+
*/
|
|
59
|
+
hasStoredSession(): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Read non-sensitive claims from the active stored login session.
|
|
62
|
+
*
|
|
63
|
+
* @returns The stored session's email, user ID, and expiration, or `null` when no usable
|
|
64
|
+
* session exists. The bearer token is never exposed.
|
|
65
|
+
* @remarks Malformed, expired, or wrong-scope stored tokens are removed before returning.
|
|
66
|
+
*/
|
|
67
|
+
getStoredSessionInfo(): Promise<StoredSessionInfo | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Clear the active login session.
|
|
70
|
+
*
|
|
71
|
+
* @returns A promise that resolves after clearing the in-memory token and attempting to
|
|
72
|
+
* remove the persisted credential.
|
|
73
|
+
* @remarks Credential-store deletion is best-effort and failures are intentionally ignored.
|
|
74
|
+
*/
|
|
75
|
+
clearStoredSession(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Activate the product using the active stored login session.
|
|
78
|
+
*
|
|
79
|
+
* @param serial - Optional reseller serial to claim and activate instead of using Product
|
|
80
|
+
* Hub's normal license selection.
|
|
81
|
+
* @returns The independent session status and the activation response, if one was available.
|
|
82
|
+
* A valid session with no matching activation returns `activation: null`.
|
|
83
|
+
* @throws {@link ProductHubError} If the API cannot be reached or an unexpected API error
|
|
84
|
+
* occurs. Authentication failures are returned as `SessionStatus.Invalid` instead.
|
|
85
|
+
* @remarks
|
|
86
|
+
* This method never performs a credential login. Missing sessions return
|
|
87
|
+
* `SessionStatus.None`; malformed, expired, wrong-scope, or API-rejected sessions return
|
|
88
|
+
* `SessionStatus.Invalid` and are removed. HTTP 404 and 409 responses return a valid session
|
|
89
|
+
* with no activation.
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const result = await apiClient.activateProductWithStoredSession();
|
|
93
|
+
* if (result.sessionStatus === SessionStatus.Valid && result.activation) {
|
|
94
|
+
* console.log(result.activation.serial);
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
activateProductWithStoredSession(serial?: string): Promise<StoredSessionActivationResult>;
|
|
99
|
+
private validateNodeVersion;
|
|
100
|
+
/**
|
|
101
|
+
* Authenticate a user and make the returned token the active session.
|
|
102
|
+
*
|
|
103
|
+
* @param email - End-user email address.
|
|
104
|
+
* @param password - End-user password.
|
|
105
|
+
* @returns The bearer token returned by Product Hub.
|
|
106
|
+
* @throws {@link NotAuthorizedError} If the credentials are rejected.
|
|
107
|
+
* @throws {@link ProductHubError} If fingerprint generation, networking, response parsing,
|
|
108
|
+
* or another API operation fails.
|
|
109
|
+
* @remarks The token is retained in memory and persisted in the operating system's secure
|
|
110
|
+
* credential store on a best-effort basis.
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const token = await apiClient.loginUser('user@example.com', 'secret');
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
loginUser(email: string, password: string): Promise<string>;
|
|
117
|
+
/**
|
|
118
|
+
* Activate a product with a license
|
|
119
|
+
*/
|
|
120
|
+
private activateProductWithToken;
|
|
121
|
+
/**
|
|
122
|
+
* Authenticate with explicit credentials and activate the product.
|
|
123
|
+
*
|
|
124
|
+
* @param params - Credentials and an optional reseller serial to claim and activate.
|
|
125
|
+
* @returns The signed Product Hub activation response.
|
|
126
|
+
* @throws {@link NotAuthorizedError} If login or activation authorization fails.
|
|
127
|
+
* @throws {@link ProductHubError} If fingerprint generation, networking, response parsing,
|
|
128
|
+
* or another API operation fails.
|
|
129
|
+
* @remarks Explicit credentials always replace the active stored session. If activation is
|
|
130
|
+
* rejected as unauthorized after login, the newly stored session is cleared.
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const activation = await apiClient.activateProduct({
|
|
134
|
+
* email: 'user@example.com',
|
|
135
|
+
* password: 'secret',
|
|
136
|
+
* serial: 'STD-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
activateProduct(params: ActivateProductParams): Promise<ActivateProductResponse>;
|
|
141
|
+
/**
|
|
142
|
+
* Activate a product using email and serial only — no login or Bearer token required.
|
|
143
|
+
*
|
|
144
|
+
* @remarks
|
|
145
|
+
* Only works when the manufacturer has "Authentication Type = None" and
|
|
146
|
+
* "Email+Serial Claiming" enabled in Product Hub. The license is claimed
|
|
147
|
+
* (if not claimed so far) and activated in a single API call.
|
|
148
|
+
*
|
|
149
|
+
* @param email - End-user email address used to identify or create the account.
|
|
150
|
+
* @param serial - License serial received after purchase.
|
|
151
|
+
* @returns The signed Product Hub activation response.
|
|
152
|
+
* @throws {@link NotAuthorizedError} If email-and-serial activation is not authorized.
|
|
153
|
+
* @throws {@link ProductHubError} If fingerprint generation, networking, response parsing,
|
|
154
|
+
* or another API operation fails.
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* const activation = await apiClient.activateProductWithEmailAndSerial(
|
|
158
|
+
* 'user@example.com',
|
|
159
|
+
* 'STD-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
|
|
160
|
+
* );
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
activateProductWithEmailAndSerial(email: string, serial: string): Promise<ActivateProductResponse>;
|
|
164
|
+
/**
|
|
165
|
+
* Activate a hardware-bound trial for the product.
|
|
166
|
+
*
|
|
167
|
+
* @returns The signed Product Hub trial response.
|
|
168
|
+
* @throws {@link ProductHubError} If fingerprint generation, networking, response parsing,
|
|
169
|
+
* or the trial API request fails.
|
|
170
|
+
* @remarks This low-level method returns API data without verifying or persisting it. Use
|
|
171
|
+
* {@link AudioPluginClient.activateTrial} for the complete plugin workflow.
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* const trial = await apiClient.activateTrial();
|
|
175
|
+
* console.log(trial.trial_days);
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
activateTrial(): Promise<ActivateTrialResponse>;
|
|
179
|
+
/**
|
|
180
|
+
* Get the latest product version from the Release distribution channel.
|
|
181
|
+
*
|
|
182
|
+
* @returns The available builds and optional update referral URL for this product.
|
|
183
|
+
* @throws {@link ProductHubError} If the request fails or its response cannot be parsed.
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* const latest = await apiClient.getLatestProductVersion();
|
|
187
|
+
* console.log(latest.builds);
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
getLatestProductVersion(): Promise<LatestProductVersionResponse>;
|
|
191
|
+
/**
|
|
192
|
+
* Get downloadable files for a specific product build.
|
|
193
|
+
*
|
|
194
|
+
* @param buildId - Product Hub build identifier.
|
|
195
|
+
* @returns The files attached to the selected build.
|
|
196
|
+
* @throws {@link ProductHubError} If the request fails or its response cannot be parsed.
|
|
197
|
+
* @example
|
|
198
|
+
* ```typescript
|
|
199
|
+
* const files = await apiClient.getBuildFiles('build-id');
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
getBuildFiles(buildId: string): Promise<BuildFile[]>;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Complete audio plugin licensing client with automatic activation management.
|
|
206
|
+
*
|
|
207
|
+
* This is the main class for integrating Gorilla Engine Product Hub licensing
|
|
208
|
+
* into your audio plugins. It handles everything from user authentication to
|
|
209
|
+
* local file persistence, signature verification, and trial management.
|
|
210
|
+
*
|
|
211
|
+
* ## Key Features
|
|
212
|
+
* - 🎫 **License Activation**: Activate full licenses with user credentials
|
|
213
|
+
* - ⏰ **Trial Management**: Start trials and track remaining time
|
|
214
|
+
* - 💾 **Local Persistence**: Automatic .ops/.lts file management
|
|
215
|
+
* - 🔄 **Subscription Auto-Refresh**: Silently refreshes persisted subscription activations when cached tokens are available
|
|
216
|
+
* - 🔒 **Signature Verification**: Built-in RSA-SHA256 cryptographic verification
|
|
217
|
+
* - 🖥️ **Hardware Fingerprinting**: Automatic system identification when used with Gorilla Engine "Hardware fingerprinting" native module
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```typescript
|
|
221
|
+
* import { ProductHub, ActivationStatus, TrialExpiredError, ProductHubError, NotAuthorizedError } from "@gorilla-engine-sdk/ge-product-hub";
|
|
222
|
+
*
|
|
223
|
+
* const client = new ProductHub.AudioPluginClient({
|
|
224
|
+
* manufacturerId: "7222d546-9c72-43d5-8bd4-1667ce390ea4",
|
|
225
|
+
* productId: "1487a36d-9bc8-4220-ba31-9998d743071f",
|
|
226
|
+
* productName: "Groove Master 3000",
|
|
227
|
+
* productPublicKey: `-----BEGIN PUBLIC KEY-----
|
|
228
|
+
* MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
|
|
229
|
+
* -----END PUBLIC KEY-----`,
|
|
230
|
+
* userResourceBaseDirectory: "/Users/<username>/Library/Application Support/<manufacturername>"
|
|
231
|
+
* });
|
|
232
|
+
*
|
|
233
|
+
* ///////////////////////////////////////////
|
|
234
|
+
* // check whether we can unlock the plugin or need to show the activation prompt
|
|
235
|
+
* if( client.isActivated() ) {
|
|
236
|
+
* // already activated - ready to go!
|
|
237
|
+
* console.log("Plugin ready to use!");
|
|
238
|
+
*
|
|
239
|
+
* // unlock via function defined below
|
|
240
|
+
* unlockPlugin();
|
|
241
|
+
*
|
|
242
|
+
* if( client.getActivationStatus() == ActivationStatus.Trial ) {
|
|
243
|
+
* // if desired: disable non-realtime bouncing when in trial mode
|
|
244
|
+
* GorillaEngine.getPluginNRTB(false);
|
|
245
|
+
* }
|
|
246
|
+
* } else {
|
|
247
|
+
* // not yet activated, neither with a trial nor regular activation
|
|
248
|
+
* showActivationOverlay();
|
|
249
|
+
* }
|
|
250
|
+
*
|
|
251
|
+
*
|
|
252
|
+
*
|
|
253
|
+
* ///////////////////////////////////////////
|
|
254
|
+
* // Handle trial activation
|
|
255
|
+
* try {
|
|
256
|
+
* const success = await client.activateTrial();
|
|
257
|
+
* if( success ) {
|
|
258
|
+
* unlockPlugin();
|
|
259
|
+
* hideActivationOverlay();
|
|
260
|
+
* showMessageBox(`Trial active. ${getRemainingTrialDays(client.remainingTrialTime())} left.`);
|
|
261
|
+
* }
|
|
262
|
+
* } catch( ex ) {
|
|
263
|
+
* if( ex instanceof TrialExpiredError ) {
|
|
264
|
+
* activationOverlay.setMessage("Trial expired. Please activate with license.");
|
|
265
|
+
* } else {
|
|
266
|
+
* activationOverlay.setMessage(`An error occurred: ${(ex as ProductHubError).message}`);
|
|
267
|
+
* }
|
|
268
|
+
* }
|
|
269
|
+
*
|
|
270
|
+
*
|
|
271
|
+
* ///////////////////////////////////////////
|
|
272
|
+
* // Handle activation with license
|
|
273
|
+
* try {
|
|
274
|
+
* const success = await client.activateProduct({
|
|
275
|
+
* email: "user@example.com",
|
|
276
|
+
* password: "secret"
|
|
277
|
+
* });
|
|
278
|
+
*
|
|
279
|
+
* if( success ) {
|
|
280
|
+
* unlockPlugin();
|
|
281
|
+
* hideActivationOverlay();
|
|
282
|
+
* aboutDialog.setSerialCodeForDisplay(client.licenseSerial());
|
|
283
|
+
* }
|
|
284
|
+
* }
|
|
285
|
+
* catch( ex ) {
|
|
286
|
+
* if( ex instanceof NotAuthorizedError ) {
|
|
287
|
+
* activationOverlay.setMessage("Invalid credentials.");
|
|
288
|
+
* } else {
|
|
289
|
+
* activationOverlay.setMessage(`An error occurred: ${(ex as ProductHubError).message}`);
|
|
290
|
+
* }
|
|
291
|
+
* }
|
|
292
|
+
*
|
|
293
|
+
*
|
|
294
|
+
* ///////////////////////////////////////////
|
|
295
|
+
* // assess the activation status of the local installation
|
|
296
|
+
* localActivationState = client.getActivationStatus();
|
|
297
|
+
* switch( localActivationState ) {
|
|
298
|
+
* case ActivationStatus.None:
|
|
299
|
+
* console.log("No successful activation found");
|
|
300
|
+
* break;
|
|
301
|
+
* case ActivationStatus.Trial:
|
|
302
|
+
* console.log("Active trial");
|
|
303
|
+
* break;
|
|
304
|
+
* case ActivationStatus.TrialExpired:
|
|
305
|
+
* console.log("Found a trial activation but the trial period is expired");
|
|
306
|
+
* break;
|
|
307
|
+
* case ActivationStatus.Licensed:
|
|
308
|
+
* console.log(`Plugin is licensed with serial ${client.licenseSerial()}`);
|
|
309
|
+
* const expires = client.licenseExpiration();
|
|
310
|
+
* if (expires) {
|
|
311
|
+
* console.log(`License expires on ${expires.toDateString()}`);
|
|
312
|
+
* }
|
|
313
|
+
* break;
|
|
314
|
+
* case ActivationStatus.SubscriptionExpired:
|
|
315
|
+
* console.log("Subscription license has expired - please renew");
|
|
316
|
+
* break;
|
|
317
|
+
* case ActivationStatus.LicenseExpired:
|
|
318
|
+
* console.log("License has expired - please renew or reactivate");
|
|
319
|
+
* break;
|
|
320
|
+
* default:
|
|
321
|
+
* console.log(`Invalid activation state: ${localActivationState}`)
|
|
322
|
+
* }
|
|
323
|
+
*
|
|
324
|
+
*
|
|
325
|
+
* ///////////////////////////////////////////
|
|
326
|
+
* // unlock audio & MIDI in your plugin
|
|
327
|
+
* function unlockPlugin(trial: boolean = false) {
|
|
328
|
+
* // Note: It is vital to uncheck the following two options in Gorilla Compiler's
|
|
329
|
+
* // "Copy Protection" tab when building your plugin:
|
|
330
|
+
* // 1. MIDI enabled on startup
|
|
331
|
+
* // 2. Audio enabled on startup
|
|
332
|
+
* //
|
|
333
|
+
* // It is better to do it this way round rather than enabling MIDI and audio in Compiler
|
|
334
|
+
* // and disabling it here when isActivated() returns false as the plugin stays unlocked
|
|
335
|
+
* // even if an exception is provoked inside its JavaScript code
|
|
336
|
+
*
|
|
337
|
+
* // Enable MIDI processing
|
|
338
|
+
* GorillaEngine.getPluginMM(true);
|
|
339
|
+
*
|
|
340
|
+
* // Enable audio processing
|
|
341
|
+
* GorillaEngine.getPluginAE(true);
|
|
342
|
+
* }
|
|
343
|
+
*
|
|
344
|
+
*
|
|
345
|
+
* ///////////////////////////////////////////
|
|
346
|
+
* // get remaining trial time in days
|
|
347
|
+
* function getRemainingTrialDays(remainingMs: number) {
|
|
348
|
+
* return Math.floor(remainingMs / (24 * 60 * 60 * 1000));
|
|
349
|
+
* }
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
class AudioPluginClient {
|
|
353
|
+
private apiClient;
|
|
354
|
+
private manufacturerId;
|
|
355
|
+
private productId;
|
|
356
|
+
private productName;
|
|
357
|
+
private productPublicKey;
|
|
358
|
+
private userResourceBaseDirectory;
|
|
359
|
+
private hwfpUtil;
|
|
360
|
+
private readonly isTestEnvironment;
|
|
361
|
+
private currentVersion;
|
|
362
|
+
private currentBuildNumber;
|
|
363
|
+
private updateCheckResult;
|
|
364
|
+
/**
|
|
365
|
+
* Create a new AudioPluginClient instance.
|
|
366
|
+
*
|
|
367
|
+
* Sets up everything needed for audio plugin licensing including hardware
|
|
368
|
+
* fingerprinting, API communication, and local file management.
|
|
369
|
+
*
|
|
370
|
+
* @remarks
|
|
371
|
+
* The constructor performs two fire-and-forget background checks:
|
|
372
|
+
* - automatic product update check (`checkForUpdates()`)
|
|
373
|
+
* - automatic silent subscription refresh (`checkUpdateSubscription()`) when
|
|
374
|
+
* both a local subscription activation and a stored login token exist
|
|
375
|
+
*
|
|
376
|
+
* These checks are not awaited by construction and may log asynchronous failures.
|
|
377
|
+
*
|
|
378
|
+
* @param options - Configuration options for the client
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```typescript
|
|
382
|
+
* const client = new ProductHub.AudioPluginClient({
|
|
383
|
+
* manufacturerId: "7222d546-9c72-43d5-8bd4-1667ce390ea4",
|
|
384
|
+
* productId: "1487a36d-9bc8-4220-ba31-9998d743071f",
|
|
385
|
+
* productName: "Groove Master 3000",
|
|
386
|
+
* productPublicKey: `-----BEGIN PUBLIC KEY-----
|
|
387
|
+
* MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
|
|
388
|
+
* -----END PUBLIC KEY-----`,
|
|
389
|
+
* userResourceBaseDirectory: "/Users/<username>/Library/Application Support/<manufacturername>"
|
|
390
|
+
* });
|
|
391
|
+
* ```
|
|
392
|
+
*
|
|
393
|
+
* @example Testing with fingerprint override
|
|
394
|
+
* ```typescript
|
|
395
|
+
* // For automated testing - never use in production!
|
|
396
|
+
* const testClient = new ProductHub.AudioPluginClient({
|
|
397
|
+
* // ... other options
|
|
398
|
+
* hardwareFingerprint: "test-fingerprint-12345"
|
|
399
|
+
* });
|
|
400
|
+
* ```
|
|
401
|
+
*
|
|
402
|
+
* @throws {@link ProductHubError} If required parameters are missing
|
|
403
|
+
*/
|
|
404
|
+
constructor(options: AudioPluginClientOptions);
|
|
405
|
+
/**
|
|
406
|
+
* Check and silently refresh persisted subscription activations when possible.
|
|
407
|
+
*
|
|
408
|
+
* If a local activation exists and is a subscription, and a login token is available
|
|
409
|
+
* in the configured credential backend, this method calls {@link updateSubscription}.
|
|
410
|
+
*
|
|
411
|
+
* @returns Promise that resolves to `true` if a newer subscription activation was persisted
|
|
412
|
+
* @remarks Returns `false` unless a local subscription and usable stored session both exist.
|
|
413
|
+
* A successful refresh may overwrite the local activation with a later expiration.
|
|
414
|
+
* @example
|
|
415
|
+
* ```typescript
|
|
416
|
+
* const refreshed = await client.checkUpdateSubscription();
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
checkUpdateSubscription(): Promise<boolean>;
|
|
420
|
+
/**
|
|
421
|
+
* Refresh an existing persisted subscription activation from the Product Hub API.
|
|
422
|
+
*
|
|
423
|
+
* This method uses the token persisted in the configured credential backend to call product
|
|
424
|
+
* activation without interactive credentials. If the retrieved subscription has a later
|
|
425
|
+
* expiration timestamp than the currently persisted subscription activation, the local
|
|
426
|
+
* activation file is overwritten.
|
|
427
|
+
*
|
|
428
|
+
* @returns Promise that resolves to `true` if local subscription activation was updated
|
|
429
|
+
* @remarks Only an existing subscription can be updated, and only when the verified remote
|
|
430
|
+
* activation expires later. Non-applicable cases and operational failures return `false`.
|
|
431
|
+
* @example
|
|
432
|
+
* ```typescript
|
|
433
|
+
* const updated = await client.updateSubscription();
|
|
434
|
+
* ```
|
|
435
|
+
*/
|
|
436
|
+
updateSubscription(): Promise<boolean>;
|
|
437
|
+
/**
|
|
438
|
+
* Activate your audio plugin with a full license using user credentials.
|
|
439
|
+
*
|
|
440
|
+
* This method authenticates the user, activates the product, verifies the activation
|
|
441
|
+
* signature, and automatically persists the activation data to local .ops files
|
|
442
|
+
* for future offline validation.
|
|
443
|
+
*
|
|
444
|
+
* @param params - User credentials for activation
|
|
445
|
+
* @returns Promise that resolves to `true` if activation was successful, `false` for network/server errors
|
|
446
|
+
* @throws {NotAuthorizedError} When email/password credentials are invalid
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```typescript
|
|
450
|
+
* try {
|
|
451
|
+
* const success = await client.activateProduct({
|
|
452
|
+
* email: "user@example.com",
|
|
453
|
+
* password: "userPassword123"
|
|
454
|
+
* });
|
|
455
|
+
*
|
|
456
|
+
* if (success) {
|
|
457
|
+
* console.log("License activated successfully!");
|
|
458
|
+
* console.log("Serial:", client.licenseSerial());
|
|
459
|
+
* } else {
|
|
460
|
+
* console.log("Activation failed, please retry");
|
|
461
|
+
* }
|
|
462
|
+
* } catch (error) {
|
|
463
|
+
* if (error instanceof NotAuthorizedError) {
|
|
464
|
+
* console.log("Invalid email or password");
|
|
465
|
+
* }
|
|
466
|
+
* }
|
|
467
|
+
* ```
|
|
468
|
+
*
|
|
469
|
+
* @remarks
|
|
470
|
+
* - Hardware fingerprint is detected automatically
|
|
471
|
+
* - Activation data is cryptographically verified before persistence
|
|
472
|
+
* - Safe to call multiple times - won't create duplicate activations
|
|
473
|
+
* - Authentication errors (wrong credentials) throw `NotAuthorizedError`
|
|
474
|
+
* - Network/server errors, missing licenses etc. return `false`
|
|
475
|
+
*/
|
|
476
|
+
activateProduct(params: AudioPluginActivationParams): Promise<boolean>;
|
|
477
|
+
/**
|
|
478
|
+
* Activate the product using only email and serial — no password or login required.
|
|
479
|
+
*
|
|
480
|
+
* The license is claimed and activated in a single call. Use this flow when the
|
|
481
|
+
* manufacturer has "Authentication Type = None" and "Email+Serial Claiming" enabled
|
|
482
|
+
* in Product Hub (i.e. no SSO provider is configured).
|
|
483
|
+
*
|
|
484
|
+
* @param params - Email and serial received from purchase
|
|
485
|
+
* @returns Promise that resolves to `true` if activation was successful, `false` otherwise
|
|
486
|
+
* @throws {NotAuthorizedError} When email+serial claiming is not enabled for this manufacturer, or the serial is not found
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* ```typescript
|
|
490
|
+
* try {
|
|
491
|
+
* const success = await client.activateProductWithSerial({
|
|
492
|
+
* email: 'user@example.com',
|
|
493
|
+
* serial: 'STD-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
|
|
494
|
+
* });
|
|
495
|
+
* if (success) {
|
|
496
|
+
* unlockPlugin();
|
|
497
|
+
* aboutDialog.setSerialCodeForDisplay(client.licenseSerial());
|
|
498
|
+
* }
|
|
499
|
+
* } catch (ex) {
|
|
500
|
+
* if (ex instanceof NotAuthorizedError) {
|
|
501
|
+
* activationOverlay.setMessage('Unable to activate. Check your email and serial code.');
|
|
502
|
+
* }
|
|
503
|
+
* }
|
|
504
|
+
* ```
|
|
505
|
+
*/
|
|
506
|
+
activateProductWithSerial(params: AudioPluginActivationWithSerialParams): Promise<boolean>;
|
|
507
|
+
/**
|
|
508
|
+
* Claim a reseller-purchased serial to the user's account and activate in one call.
|
|
509
|
+
*
|
|
510
|
+
* Use this when a user already has an account (SSO login) but bought a license
|
|
511
|
+
* serial from a reseller shop. The serial is claimed to their account and then
|
|
512
|
+
* activated, all in a single operation.
|
|
513
|
+
*
|
|
514
|
+
* This method always logs in with the supplied credentials. To claim a serial using
|
|
515
|
+
* the active stored session, call {@link claimAndActivateLicenseWithStoredSession}.
|
|
516
|
+
*
|
|
517
|
+
* @param params - User credentials and reseller serial
|
|
518
|
+
* @returns Promise that resolves to `true` if activation was successful, `false` otherwise
|
|
519
|
+
* @throws {@link NotAuthorizedError} When the supplied credentials are invalid.
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* ```typescript
|
|
523
|
+
* try {
|
|
524
|
+
* const success = await client.claimAndActivateLicenseWithSerial({
|
|
525
|
+
* email: 'user@example.com',
|
|
526
|
+
* password: 'secret',
|
|
527
|
+
* serial: 'STD-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
|
|
528
|
+
* });
|
|
529
|
+
* if (success) {
|
|
530
|
+
* unlockPlugin();
|
|
531
|
+
* aboutDialog.setSerialCodeForDisplay(client.licenseSerial());
|
|
532
|
+
* }
|
|
533
|
+
* } catch (ex) {
|
|
534
|
+
* if (ex instanceof NotAuthorizedError) {
|
|
535
|
+
* activationOverlay.setMessage('Invalid credentials or serial already owned by another account.');
|
|
536
|
+
* }
|
|
537
|
+
* }
|
|
538
|
+
* ```
|
|
539
|
+
*
|
|
540
|
+
* @remarks A verified activation is persisted locally. Missing, disabled, or conflicting
|
|
541
|
+
* serials and other non-authentication failures return `false`.
|
|
542
|
+
*/
|
|
543
|
+
claimAndActivateLicenseWithSerial(params: AudioPluginClaimAndActivateParams): Promise<boolean>;
|
|
544
|
+
/**
|
|
545
|
+
* Claim a reseller serial and activate it using the active stored session.
|
|
546
|
+
*
|
|
547
|
+
* @param params - Reseller serial to claim and activate.
|
|
548
|
+
* @returns `true` when a signed activation is verified and persisted; otherwise `false`.
|
|
549
|
+
* @remarks
|
|
550
|
+
* This method never performs a credential login. Missing or invalid sessions, serial
|
|
551
|
+
* conflicts, network failures, and invalid activation signatures are converted to `false`.
|
|
552
|
+
* Use {@link restoreActivationFromStoredSession} when the caller needs independent session
|
|
553
|
+
* and activation statuses.
|
|
554
|
+
* @example
|
|
555
|
+
* ```typescript
|
|
556
|
+
* const activated = await client.claimAndActivateLicenseWithStoredSession({
|
|
557
|
+
* serial: 'STD-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
|
|
558
|
+
* });
|
|
559
|
+
* ```
|
|
560
|
+
*/
|
|
561
|
+
claimAndActivateLicenseWithStoredSession(params: AudioPluginStoredSessionSerialParams): Promise<boolean>;
|
|
562
|
+
/**
|
|
563
|
+
* Check whether a usable login session is stored for this product and device.
|
|
564
|
+
*
|
|
565
|
+
* @returns A promise resolving to `true` when a usable session exists; otherwise `false`.
|
|
566
|
+
* @remarks Invalid stored tokens are removed by the underlying credential-store check.
|
|
567
|
+
*/
|
|
568
|
+
hasStoredSession(): Promise<boolean>;
|
|
569
|
+
/**
|
|
570
|
+
* Read non-sensitive claims from the active stored login session.
|
|
571
|
+
*
|
|
572
|
+
* @returns The stored session's email, user ID, and expiration, or `null` when no usable
|
|
573
|
+
* session exists. The bearer token is never exposed.
|
|
574
|
+
* @example
|
|
575
|
+
* ```typescript
|
|
576
|
+
* const session = await client.getStoredSessionInfo();
|
|
577
|
+
* if (session) console.log(session.email, session.expiresAt);
|
|
578
|
+
* ```
|
|
579
|
+
*/
|
|
580
|
+
getStoredSessionInfo(): Promise<StoredSessionInfo | null>;
|
|
581
|
+
/**
|
|
582
|
+
* Clear the active stored login session.
|
|
583
|
+
*
|
|
584
|
+
* @returns A promise that resolves after the in-memory token and persisted credential have
|
|
585
|
+
* been cleared on a best-effort basis.
|
|
586
|
+
* @remarks This does not remove the locally persisted `.ops` activation file.
|
|
587
|
+
* @example
|
|
588
|
+
* ```typescript
|
|
589
|
+
* await client.clearStoredSession();
|
|
590
|
+
* ```
|
|
591
|
+
*/
|
|
592
|
+
clearStoredSession(): Promise<void>;
|
|
593
|
+
/**
|
|
594
|
+
* Restore product activation using the active stored session.
|
|
595
|
+
*
|
|
596
|
+
* @returns Independent session validity and local product activation statuses.
|
|
597
|
+
* @throws {@link ProductHubError} If the API request fails unexpectedly or the returned
|
|
598
|
+
* activation has an invalid signature.
|
|
599
|
+
* @remarks
|
|
600
|
+
* Session validity and product activation are independent: a valid session can return an
|
|
601
|
+
* unlicensed or expired activation status. Valid signed activations are persisted locally;
|
|
602
|
+
* invalid sessions are removed by the underlying API client.
|
|
603
|
+
* @example
|
|
604
|
+
* ```typescript
|
|
605
|
+
* const result = await client.restoreActivationFromStoredSession();
|
|
606
|
+
* if (
|
|
607
|
+
* result.activationStatus === ActivationStatus.Licensed ||
|
|
608
|
+
* result.activationStatus === ActivationStatus.Subscription
|
|
609
|
+
* ) {
|
|
610
|
+
* unlockPlugin();
|
|
611
|
+
* }
|
|
612
|
+
* ```
|
|
613
|
+
*/
|
|
614
|
+
restoreActivationFromStoredSession(): Promise<ActivationRestoreResult>;
|
|
615
|
+
/**
|
|
616
|
+
* Activate a trial period for your audio plugin.
|
|
617
|
+
*
|
|
618
|
+
* Starts a new trial or reuses an existing valid trial activation.
|
|
619
|
+
* No user authentication is required - trials are tied to the hardware fingerprint.
|
|
620
|
+
* The trial data is automatically verified and persisted to local .ops files.
|
|
621
|
+
*
|
|
622
|
+
* @returns Promise that resolves to `true` if trial activation was successful, `false` otherwise
|
|
623
|
+
* @throws {TrialExpiredError} When a trial was already used on this machine and has expired
|
|
624
|
+
*
|
|
625
|
+
* @example
|
|
626
|
+
* ```typescript
|
|
627
|
+
* const success = await client.activateTrial();
|
|
628
|
+
*
|
|
629
|
+
* if (success) {
|
|
630
|
+
* const remainingMs = client.remainingTrialTime();
|
|
631
|
+
* const days = Math.floor(remainingMs / (24 * 60 * 60 * 1000));
|
|
632
|
+
* console.log(`Trial activated! ${days} days remaining.`);
|
|
633
|
+
* } else {
|
|
634
|
+
* console.log("Trial activation failed");
|
|
635
|
+
* }
|
|
636
|
+
* ```
|
|
637
|
+
*
|
|
638
|
+
* @remarks
|
|
639
|
+
* - Hardware fingerprint prevents trial abuse across different machines
|
|
640
|
+
* - Trial period is determined by Product Hub configuration
|
|
641
|
+
* - Automatically updates last launch time
|
|
642
|
+
* - Expired trials throw `TrialExpiredError`
|
|
643
|
+
* - Safe to call multiple times - reuses existing valid trials
|
|
644
|
+
*/
|
|
645
|
+
activateTrial(): Promise<boolean>;
|
|
646
|
+
/**
|
|
647
|
+
* Check if the plugin is activated with a full license.
|
|
648
|
+
*
|
|
649
|
+
* Verifies that a valid license activation exists locally, including
|
|
650
|
+
* signature verification and hardware fingerprint validation.
|
|
651
|
+
*
|
|
652
|
+
* @returns `true` if the plugin has a valid full license, `false` otherwise
|
|
653
|
+
*
|
|
654
|
+
* @example
|
|
655
|
+
* ```typescript
|
|
656
|
+
* if (client.isActivatedWithLicense()) {
|
|
657
|
+
* console.log("Full license active!");
|
|
658
|
+
* console.log("License serial:", client.licenseSerial());
|
|
659
|
+
* } else {
|
|
660
|
+
* console.log("No license - maybe try activation or trial");
|
|
661
|
+
* }
|
|
662
|
+
* ```
|
|
663
|
+
*
|
|
664
|
+
* @remarks
|
|
665
|
+
* - Validates hardware fingerprint to prevent license transfer
|
|
666
|
+
* - Safe to call frequently - uses cached local data
|
|
667
|
+
*/
|
|
668
|
+
isActivatedWithLicense(): boolean;
|
|
669
|
+
/**
|
|
670
|
+
* Get the remaining trial time in milliseconds.
|
|
671
|
+
*
|
|
672
|
+
* Calculates how much time is left in the current trial period, including
|
|
673
|
+
* signature verification and hardware fingerprint validation. Returns 0
|
|
674
|
+
* if no valid trial exists or if the trial has expired.
|
|
675
|
+
*
|
|
676
|
+
* @returns Remaining trial time in milliseconds, or 0 if no valid trial
|
|
677
|
+
*
|
|
678
|
+
* @example
|
|
679
|
+
* ```typescript
|
|
680
|
+
* const remainingMs = client.remainingTrialTime();
|
|
681
|
+
*
|
|
682
|
+
* if (remainingMs > 0) {
|
|
683
|
+
* const days = Math.floor(remainingMs / (24 * 60 * 60 * 1000));
|
|
684
|
+
* const hours = Math.floor((remainingMs % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
|
|
685
|
+
* console.log(`Trial: ${days} days, ${hours} hours remaining`);
|
|
686
|
+
* } else {
|
|
687
|
+
* console.log("No active trial");
|
|
688
|
+
* }
|
|
689
|
+
* ```
|
|
690
|
+
*
|
|
691
|
+
* @remarks
|
|
692
|
+
* - Automatically updates last launch time when called
|
|
693
|
+
* - Performs cryptographic verification of trial data
|
|
694
|
+
* - Returns exact milliseconds for precise timing calculations
|
|
695
|
+
*/
|
|
696
|
+
remainingTrialTime(): number;
|
|
697
|
+
/**
|
|
698
|
+
* Check if the plugin is activated and ready to use.
|
|
699
|
+
*
|
|
700
|
+
* Returns `true` if the plugin has either a valid full license OR a valid trial
|
|
701
|
+
* with remaining time. This is the primary method to check if your plugin
|
|
702
|
+
* should be functional.
|
|
703
|
+
*
|
|
704
|
+
* @returns `true` if plugin is activated (licensed or trial), `false` otherwise
|
|
705
|
+
*
|
|
706
|
+
* @example
|
|
707
|
+
* ```typescript
|
|
708
|
+
* // Basic usage
|
|
709
|
+
* if (client.isActivated()) {
|
|
710
|
+
* // Enable all plugin features
|
|
711
|
+
* enableAudioProcessing();
|
|
712
|
+
* } else {
|
|
713
|
+
* // Show activation dialog or disable features
|
|
714
|
+
* showActivationDialog();
|
|
715
|
+
* }
|
|
716
|
+
*
|
|
717
|
+
* // Advanced usage with status details
|
|
718
|
+
* if (client.isActivated()) {
|
|
719
|
+
* if (client.isActivatedWithLicense()) {
|
|
720
|
+
* console.log("Full license - all features activated");
|
|
721
|
+
* } else {
|
|
722
|
+
* const days = Math.floor(client.remainingTrialTime() / (24 * 60 * 60 * 1000));
|
|
723
|
+
* console.log(`Trial mode - ${days} days remaining`);
|
|
724
|
+
* }
|
|
725
|
+
* }
|
|
726
|
+
* ```
|
|
727
|
+
*
|
|
728
|
+
* @remarks
|
|
729
|
+
* - This is typically the main method you'll use in your plugin logic
|
|
730
|
+
* - Combines both license and trial validation
|
|
731
|
+
* - Efficient - uses cached data where possible
|
|
732
|
+
*/
|
|
733
|
+
isActivated(): boolean;
|
|
734
|
+
/**
|
|
735
|
+
* Get detailed activation status information.
|
|
736
|
+
*
|
|
737
|
+
* Provides more granular information about the current activation state
|
|
738
|
+
* than the simple boolean methods. Useful for showing specific UI states
|
|
739
|
+
* or handling different scenarios in your plugin.
|
|
740
|
+
*
|
|
741
|
+
* @returns Current activation status as an enum value
|
|
742
|
+
*
|
|
743
|
+
* @example
|
|
744
|
+
* ```typescript
|
|
745
|
+
* import { ActivationStatus } from "@gorilla-engine-sdk/ge-product-hub";
|
|
746
|
+
*
|
|
747
|
+
* switch (client.getActivationStatus()) {
|
|
748
|
+
* case ActivationStatus.Licensed:
|
|
749
|
+
* showLicensedUI();
|
|
750
|
+
* console.log("Serial:", client.licenseSerial());
|
|
751
|
+
* break;
|
|
752
|
+
*
|
|
753
|
+
* case ActivationStatus.Trial:
|
|
754
|
+
* const days = Math.floor(client.remainingTrialTime() / (24 * 60 * 60 * 1000));
|
|
755
|
+
* showTrialUI(days);
|
|
756
|
+
* break;
|
|
757
|
+
*
|
|
758
|
+
* case ActivationStatus.TrialExpired:
|
|
759
|
+
* showTrialExpiredUI();
|
|
760
|
+
* break;
|
|
761
|
+
*
|
|
762
|
+
* case ActivationStatus.None:
|
|
763
|
+
* case ActivationStatus.LicenseExpired:
|
|
764
|
+
* case ActivationStatus.SubscriptionExpired:
|
|
765
|
+
* showActivationRequiredUI();
|
|
766
|
+
* break;
|
|
767
|
+
* }
|
|
768
|
+
* ```
|
|
769
|
+
*
|
|
770
|
+
* @see {@link ActivationStatus} for all possible status values
|
|
771
|
+
*
|
|
772
|
+
* @remarks
|
|
773
|
+
* - More informative than `isActivated()` or `isActivatedWithLicense()`
|
|
774
|
+
* - Helps tailor user experience based on exact activation state
|
|
775
|
+
* - Always returns a valid enum value
|
|
776
|
+
* - Note that this is the local activation status. This is especially important in regard to trials as there can be a possible edge case.
|
|
777
|
+
If the user trialed the product in the past and then later deleted the installation and they now want to trial again, the local activation state would be `None` and
|
|
778
|
+
`activateTrial()` would throw `TrialExpiredError` with the local activation state staying `None`. If on the other hand the installation is not deleted so the activation
|
|
779
|
+
file still exists, the local activation state would be `TrialExpired`.
|
|
780
|
+
*/
|
|
781
|
+
getActivationStatus(): ActivationStatus;
|
|
782
|
+
/**
|
|
783
|
+
* Get the license serial number if the plugin is fully activated.
|
|
784
|
+
*
|
|
785
|
+
* Returns the unique serial number associated with the current license
|
|
786
|
+
* activation. Useful for support purposes, logging, or displaying
|
|
787
|
+
* license information to users.
|
|
788
|
+
*
|
|
789
|
+
* @returns License serial number if licensed, empty string otherwise
|
|
790
|
+
*
|
|
791
|
+
* @example
|
|
792
|
+
* ```typescript
|
|
793
|
+
* const serial = client.licenseSerial();
|
|
794
|
+
*
|
|
795
|
+
* if (serial) {
|
|
796
|
+
* console.log(`Licensed version - Serial: ${serial}`);
|
|
797
|
+
* // Maybe show in about dialog
|
|
798
|
+
* showAboutDialog({ serial });
|
|
799
|
+
* } else {
|
|
800
|
+
* console.log("Not licensed");
|
|
801
|
+
* }
|
|
802
|
+
* ```
|
|
803
|
+
*
|
|
804
|
+
* @remarks
|
|
805
|
+
* - Only returns a value when `isActivatedWithLicense()` is `true`
|
|
806
|
+
* - Serial numbers are unique per license activation
|
|
807
|
+
* - Useful for customer support and license tracking
|
|
808
|
+
*/
|
|
809
|
+
licenseSerial(): string;
|
|
810
|
+
/**
|
|
811
|
+
* Get the type of the current license.
|
|
812
|
+
*
|
|
813
|
+
* Returns the license type (Standard, NFR, Free, or Subscription) if the
|
|
814
|
+
* plugin is activated with a valid license. Returns null for trial activations
|
|
815
|
+
* or when no valid license exists.
|
|
816
|
+
*
|
|
817
|
+
* @returns License type if activated with license, null otherwise
|
|
818
|
+
*
|
|
819
|
+
* @example
|
|
820
|
+
* ```typescript
|
|
821
|
+
* const type = client.licenseType();
|
|
822
|
+
* if (type) {
|
|
823
|
+
* console.log(`License type: ${type}`);
|
|
824
|
+
* if (type === LicenseType.Subscription) {
|
|
825
|
+
* console.log("Subscription license - check expiration");
|
|
826
|
+
* }
|
|
827
|
+
* }
|
|
828
|
+
* ```
|
|
829
|
+
*
|
|
830
|
+
* @remarks
|
|
831
|
+
* - Returns null for trials (use `getActivationStatus()` to check for trials)
|
|
832
|
+
* - Useful for displaying license information to users
|
|
833
|
+
* - Only meaningful when `isActivatedWithLicense()` is `true`
|
|
834
|
+
*/
|
|
835
|
+
licenseType(): LicenseType | null;
|
|
836
|
+
/**
|
|
837
|
+
* Check if the current license is time-limited (subscription or expiring).
|
|
838
|
+
*
|
|
839
|
+
* Returns `true` if the persisted license activation has an expiration date.
|
|
840
|
+
*
|
|
841
|
+
* @returns `true` if license is time-limited, `false` if perpetual, trial or no license
|
|
842
|
+
*
|
|
843
|
+
* @example
|
|
844
|
+
* ```typescript
|
|
845
|
+
* if (client.isTimeLimitedLicense()) {
|
|
846
|
+
* const expires = client.licenseExpiration();
|
|
847
|
+
* if (expires) {
|
|
848
|
+
* console.log(`License expires on ${expires.toDateString()}`);
|
|
849
|
+
* }
|
|
850
|
+
* } else {
|
|
851
|
+
* console.log("Perpetual license");
|
|
852
|
+
* }
|
|
853
|
+
* ```
|
|
854
|
+
*
|
|
855
|
+
* @remarks
|
|
856
|
+
* - This method does not verify the persisted activation or check whether it has expired
|
|
857
|
+
* - Helps determine if renewal reminders are needed
|
|
858
|
+
* - Time-limited licenses have an `expires` date in the activation data
|
|
859
|
+
*/
|
|
860
|
+
isTimeLimitedLicense(): boolean;
|
|
861
|
+
/**
|
|
862
|
+
* Get the expiration date from the persisted license activation.
|
|
863
|
+
*
|
|
864
|
+
* Returns the persisted expiration date, or null if the license is perpetual
|
|
865
|
+
* (never expires), no license activation exists, or the activation is a trial.
|
|
866
|
+
* For trials, use `remainingTrialTime()` to check remaining time.
|
|
867
|
+
*
|
|
868
|
+
* @returns Expiration date if licensed and has expiration, null otherwise (even for active trials)
|
|
869
|
+
*
|
|
870
|
+
* @example
|
|
871
|
+
* ```typescript
|
|
872
|
+
* const expires = client.licenseExpiration();
|
|
873
|
+
* if (expires) {
|
|
874
|
+
* const daysLeft = Math.ceil((expires.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
|
|
875
|
+
* console.log(`License expires in ${daysLeft} days`);
|
|
876
|
+
* } else {
|
|
877
|
+
* console.log("Perpetual license");
|
|
878
|
+
* }
|
|
879
|
+
* ```
|
|
880
|
+
*
|
|
881
|
+
* @remarks This method does not verify the persisted activation or check whether the date
|
|
882
|
+
* has passed. Use {@link getActivationStatus} to determine current validity.
|
|
883
|
+
*/
|
|
884
|
+
licenseExpiration(): Date | null;
|
|
885
|
+
/**
|
|
886
|
+
* Write an offline activation file for support purposes.
|
|
887
|
+
*
|
|
888
|
+
* This method creates an offline activation file (`.ops`) containing your product's hardware
|
|
889
|
+
* fingerprint and configuration details. This is useful when end users don't have internet
|
|
890
|
+
* access - they can send you this file to obtain their system information, allowing you to
|
|
891
|
+
* create a manual activation in the Product Hub backend and provide them with a signed
|
|
892
|
+
* activation file for offline use.
|
|
893
|
+
*
|
|
894
|
+
* @param options - Configuration options for the offline activation file
|
|
895
|
+
* @returns Nothing. Writes `{productName}.ops`, or leaves an existing file untouched when
|
|
896
|
+
* `overwriteExisting` is `false`.
|
|
897
|
+
* @throws {@link ProductHubError} If hardware fingerprint generation fails.
|
|
898
|
+
* @throws {@link Error} If the destination cannot be created or written.
|
|
899
|
+
*
|
|
900
|
+
* @example
|
|
901
|
+
* ```typescript
|
|
902
|
+
* // Write to default location without overwriting
|
|
903
|
+
* client.writeOfflineActivationFile();
|
|
904
|
+
*
|
|
905
|
+
* // Write to custom location with overwrite enabled
|
|
906
|
+
* client.writeOfflineActivationFile({
|
|
907
|
+
* customFolderPath: "/Users/username/Desktop",
|
|
908
|
+
* overwriteExisting: true
|
|
909
|
+
* });
|
|
910
|
+
*
|
|
911
|
+
* // Just enable overwriting in default location
|
|
912
|
+
* client.writeOfflineActivationFile({ overwriteExisting: true });
|
|
913
|
+
* ```
|
|
914
|
+
*
|
|
915
|
+
* @remarks
|
|
916
|
+
* - The file contains hardware fingerprint, product ID, and signature versions
|
|
917
|
+
* - File is named `{productName}.ops` (e.g., "MyPlugin.ops")
|
|
918
|
+
* - Safe to call multiple times - respects `overwriteExisting` option
|
|
919
|
+
* - Automatically creates necessary directories
|
|
920
|
+
* - For offline activation workflow with customer support
|
|
921
|
+
*/
|
|
922
|
+
writeOfflineActivationFile(options?: OfflineActivationFileOptions): void;
|
|
923
|
+
/**
|
|
924
|
+
* Verify activation signature (v6 format only)
|
|
925
|
+
*/
|
|
926
|
+
private verifyActivation;
|
|
927
|
+
/**
|
|
928
|
+
* Verify trial signature
|
|
929
|
+
*/
|
|
930
|
+
private verifyTrial;
|
|
931
|
+
private opsFileFolderPath;
|
|
932
|
+
private opsFilePath;
|
|
933
|
+
private ltsFilePath;
|
|
934
|
+
private persistActivationOnDisk;
|
|
935
|
+
private persistTrialActivationOnDisk;
|
|
936
|
+
private loadActivationFromDisk;
|
|
937
|
+
private loadTrialActivationFromDisk;
|
|
938
|
+
private updateLastTrialLaunchTime;
|
|
939
|
+
private readLastTrialLaunchTime;
|
|
940
|
+
/**
|
|
941
|
+
* Check for product updates from the Product Hub API.
|
|
942
|
+
*
|
|
943
|
+
* This method queries the latest version available in the Release distribution channel
|
|
944
|
+
* and compares it with the currently installed version. Results are cached and can
|
|
945
|
+
* be accessed via `isUpdateAvailable()`, `getUpdateReferralURL()`, and `getUpdateFiles()`.
|
|
946
|
+
*
|
|
947
|
+
* The method is automatically called once during construction but can be called again
|
|
948
|
+
* to re-check for updates (e.g., if the initial check failed due to network issues).
|
|
949
|
+
*
|
|
950
|
+
* @returns Promise that resolves to `true` if the check succeeded, `false` if it failed
|
|
951
|
+
*
|
|
952
|
+
* @example
|
|
953
|
+
* ```typescript
|
|
954
|
+
* // Manual re-check for updates
|
|
955
|
+
* const success = await client.checkForUpdates();
|
|
956
|
+
* if (success && client.isUpdateAvailable()) {
|
|
957
|
+
* console.log("Update available!");
|
|
958
|
+
* }
|
|
959
|
+
* ```
|
|
960
|
+
*/
|
|
961
|
+
checkForUpdates(): Promise<boolean>;
|
|
962
|
+
/**
|
|
963
|
+
* Check if an update is available for this product.
|
|
964
|
+
*
|
|
965
|
+
* @returns `true` if an update is available, `false` otherwise
|
|
966
|
+
*
|
|
967
|
+
* @remarks
|
|
968
|
+
* Returns `false` if the update check hasn't been performed yet, failed,
|
|
969
|
+
* or if no update is available.
|
|
970
|
+
*
|
|
971
|
+
* @example
|
|
972
|
+
* ```typescript
|
|
973
|
+
* if (client.isUpdateAvailable()) {
|
|
974
|
+
* console.log("New version available!");
|
|
975
|
+
* console.log("Download from:", client.getUpdateReferralURL());
|
|
976
|
+
* }
|
|
977
|
+
* ```
|
|
978
|
+
*/
|
|
979
|
+
isUpdateAvailable(): boolean;
|
|
980
|
+
/**
|
|
981
|
+
* Get the update referral URL for this product.
|
|
982
|
+
*
|
|
983
|
+
* This URL can be used to direct users to a download page or update instructions.
|
|
984
|
+
* The URL is configured per-product in the Product Hub web interface.
|
|
985
|
+
*
|
|
986
|
+
* @returns The update referral URL, or `null` if not available or check failed
|
|
987
|
+
*
|
|
988
|
+
* @example
|
|
989
|
+
* ```typescript
|
|
990
|
+
* const url = client.getUpdateReferralURL();
|
|
991
|
+
* if (url) {
|
|
992
|
+
* // Open URL in browser or show to user
|
|
993
|
+
* console.log("Visit:", url);
|
|
994
|
+
* }
|
|
995
|
+
* ```
|
|
996
|
+
*/
|
|
997
|
+
getUpdateReferralURL(): string | null;
|
|
998
|
+
/**
|
|
999
|
+
* Get the downloadable files for the latest product update.
|
|
1000
|
+
*
|
|
1001
|
+
* Returns an array of files (installers, packages, etc.) that can be downloaded
|
|
1002
|
+
* to update the product. Files are specific to the current operating system.
|
|
1003
|
+
*
|
|
1004
|
+
* @returns Promise that resolves to an array of build files, or empty array if unavailable
|
|
1005
|
+
*
|
|
1006
|
+
* @remarks
|
|
1007
|
+
* - Returns empty array if update check failed or no update is available
|
|
1008
|
+
* - Files are automatically filtered for the current operating system
|
|
1009
|
+
* - Each file includes: id, name, size, sha256 hash, and download URL
|
|
1010
|
+
*
|
|
1011
|
+
* @example
|
|
1012
|
+
* ```typescript
|
|
1013
|
+
* const files = await client.getUpdateFiles();
|
|
1014
|
+
* for (const file of files) {
|
|
1015
|
+
* console.log(`Download: ${file.name} (${file.size} bytes)`);
|
|
1016
|
+
* console.log(`URL: ${file.url}`);
|
|
1017
|
+
* console.log(`SHA256: ${file.sha256}`);
|
|
1018
|
+
* }
|
|
1019
|
+
* ```
|
|
1020
|
+
*/
|
|
1021
|
+
getUpdateFiles(): Promise<BuildFile[]>;
|
|
1022
|
+
/**
|
|
1023
|
+
* Detect the current operating system.
|
|
1024
|
+
* @private
|
|
1025
|
+
*/
|
|
1026
|
+
private detectOperatingSystem;
|
|
1027
|
+
/**
|
|
1028
|
+
* Select the appropriate build for the given OS.
|
|
1029
|
+
* Prefers exact OS match over "any".
|
|
1030
|
+
* @private
|
|
1031
|
+
*/
|
|
1032
|
+
private selectBuildForOS;
|
|
1033
|
+
/**
|
|
1034
|
+
* Check if the remote build version is newer than the current version.
|
|
1035
|
+
* @private
|
|
1036
|
+
*/
|
|
1037
|
+
private isNewerVersion;
|
|
1038
|
+
}
|
|
1039
|
+
}
|