@moonbase.sh/licensing 1.0.4 → 1.0.7
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 +97 -0
- package/dist/index.cjs +16 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +16 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @moonbase.sh/licensing
|
|
2
|
+
|
|
3
|
+
Node.js licensing SDK for Moonbase products.
|
|
4
|
+
|
|
5
|
+
Use it to request activation, validate licenses locally and online, persist licenses, and revoke activations.
|
|
6
|
+
|
|
7
|
+
Learn more in our official documentation here: https://moonbase.sh/docs/licensing/sdks/node/
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @moonbase.sh/licensing
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Create a licensing client
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { FileLicenseStore, MoonbaseLicensing } from '@moonbase.sh/licensing'
|
|
19
|
+
|
|
20
|
+
const licensing = new MoonbaseLicensing({
|
|
21
|
+
endpoint: 'https://demo.moonbase.sh',
|
|
22
|
+
productId: 'demo-app',
|
|
23
|
+
publicKey: process.env.MOONBASE_PUBLIC_KEY!,
|
|
24
|
+
accountId: process.env.MOONBASE_ACCOUNT_ID,
|
|
25
|
+
|
|
26
|
+
// Optionally adjust the license store with path
|
|
27
|
+
// to where the license should be stored, or use
|
|
28
|
+
// alternate storage mechanisms to persist the token.
|
|
29
|
+
licenseStore: new FileLicenseStore(),
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- `publicKey` is the Moonbase public key used to verify signed license tokens.
|
|
34
|
+
- `FileLicenseStore` persists the license locally (`license.mb` by default).
|
|
35
|
+
|
|
36
|
+
## Activation flow
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
const request = await licensing.client.requestActivation()
|
|
40
|
+
|
|
41
|
+
console.log('Open this URL in a browser:', request.browser)
|
|
42
|
+
|
|
43
|
+
let license = null
|
|
44
|
+
while (!license) {
|
|
45
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
46
|
+
license = await licensing.client.getRequestedActivation(request)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await licensing.store.storeLocalLicense(license)
|
|
50
|
+
console.log('License stored locally')
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Validate on startup
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const localLicense = await licensing.store.loadLocalLicense()
|
|
57
|
+
|
|
58
|
+
if (localLicense) {
|
|
59
|
+
// Validate token signature + device binding locally
|
|
60
|
+
const locallyValidated = await licensing.validator.validateLicense(localLicense.token)
|
|
61
|
+
|
|
62
|
+
// Re-validate against Moonbase (recommended for online activations)
|
|
63
|
+
const refreshed = await licensing.client.validateLicense(locallyValidated)
|
|
64
|
+
await licensing.store.storeLocalLicense(refreshed)
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Revoke a license activation
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const localLicense = await licensing.store.loadLocalLicense()
|
|
72
|
+
|
|
73
|
+
if (localLicense) {
|
|
74
|
+
await licensing.client.revokeLicense(localLicense)
|
|
75
|
+
await licensing.store.deleteLocalLicense()
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Offline helpers
|
|
80
|
+
|
|
81
|
+
Generate a device token to support offline activation workflows:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const deviceToken = await licensing.generateDeviceToken()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Read and validate raw license bytes (for example from a file):
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const license = await licensing.readRawLicense(rawLicenseBuffer)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Custom stores and device resolvers
|
|
94
|
+
|
|
95
|
+
You can inject your own `ILicenseStore` and `IDeviceIdResolver` implementations.
|
|
96
|
+
|
|
97
|
+
Note: the current configuration property name for custom device resolver is `deivceIdResolver`.
|
package/dist/index.cjs
CHANGED
|
@@ -127,6 +127,22 @@ var LicenseClient = class {
|
|
|
127
127
|
if (response.status === 204 || response.status === 404) return null;
|
|
128
128
|
return await this.handleLicenseResponse(response);
|
|
129
129
|
}
|
|
130
|
+
async requestTrial() {
|
|
131
|
+
const content = {
|
|
132
|
+
deviceName: await this.deviceIdResolver.resolveDeviceName(),
|
|
133
|
+
deviceSignature: await this.deviceIdResolver.resolveDeviceId()
|
|
134
|
+
};
|
|
135
|
+
const response = await (0, import_cross_fetch.default)(this.configuration.endpoint + `/api/client/trials/${this.configuration.productId}/request?format=JWT`, {
|
|
136
|
+
...defaultFetchOptions,
|
|
137
|
+
method: "POST",
|
|
138
|
+
headers: {
|
|
139
|
+
...defaultFetchOptions.headers,
|
|
140
|
+
"Content-Type": "application/json"
|
|
141
|
+
},
|
|
142
|
+
body: JSON.stringify(content)
|
|
143
|
+
});
|
|
144
|
+
return await this.handleLicenseResponse(response);
|
|
145
|
+
}
|
|
130
146
|
async validateLicense(license) {
|
|
131
147
|
const response = await (0, import_cross_fetch.default)(this.configuration.endpoint + `/api/client/licenses/${this.configuration.productId}/validate?format=JWT`, {
|
|
132
148
|
...defaultFetchOptions,
|
package/dist/index.d.cts
CHANGED
|
@@ -159,6 +159,15 @@ interface ILicenseClient {
|
|
|
159
159
|
* @returns A license if the request has been fulfilled, else null
|
|
160
160
|
*/
|
|
161
161
|
getRequestedActivation(request: ActivationRequestResponse): Promise<License | null>;
|
|
162
|
+
/**
|
|
163
|
+
* Requests a trial license for the product.
|
|
164
|
+
* This can only be done once per product per device, and skips
|
|
165
|
+
* the browser activation process. This currently requires that
|
|
166
|
+
* the product allows anonymous trials, since there is no authentication.
|
|
167
|
+
*
|
|
168
|
+
* @returns The allocated trial license, throws if the trial license cannot be allocated (e.g. user already had a trial) or if the request failed
|
|
169
|
+
*/
|
|
170
|
+
requestTrial(): Promise<License>;
|
|
162
171
|
/**
|
|
163
172
|
* Checks if the given license is still valid, not revoked
|
|
164
173
|
* and returns an updated license if still active.
|
|
@@ -194,6 +203,7 @@ declare class LicenseClient implements ILicenseClient {
|
|
|
194
203
|
constructor(configuration: MoonbaseConfiguration, deviceIdResolver: IDeviceIdResolver, licenseValidator: ILicenseValidator);
|
|
195
204
|
requestActivation(): Promise<ActivationRequestResponse>;
|
|
196
205
|
getRequestedActivation(request: ActivationRequestResponse): Promise<License | null>;
|
|
206
|
+
requestTrial(): Promise<License>;
|
|
197
207
|
validateLicense(license: License): Promise<License>;
|
|
198
208
|
validateRawLicense(rawLicense: Buffer): Promise<License>;
|
|
199
209
|
revokeLicense(license: License): Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -159,6 +159,15 @@ interface ILicenseClient {
|
|
|
159
159
|
* @returns A license if the request has been fulfilled, else null
|
|
160
160
|
*/
|
|
161
161
|
getRequestedActivation(request: ActivationRequestResponse): Promise<License | null>;
|
|
162
|
+
/**
|
|
163
|
+
* Requests a trial license for the product.
|
|
164
|
+
* This can only be done once per product per device, and skips
|
|
165
|
+
* the browser activation process. This currently requires that
|
|
166
|
+
* the product allows anonymous trials, since there is no authentication.
|
|
167
|
+
*
|
|
168
|
+
* @returns The allocated trial license, throws if the trial license cannot be allocated (e.g. user already had a trial) or if the request failed
|
|
169
|
+
*/
|
|
170
|
+
requestTrial(): Promise<License>;
|
|
162
171
|
/**
|
|
163
172
|
* Checks if the given license is still valid, not revoked
|
|
164
173
|
* and returns an updated license if still active.
|
|
@@ -194,6 +203,7 @@ declare class LicenseClient implements ILicenseClient {
|
|
|
194
203
|
constructor(configuration: MoonbaseConfiguration, deviceIdResolver: IDeviceIdResolver, licenseValidator: ILicenseValidator);
|
|
195
204
|
requestActivation(): Promise<ActivationRequestResponse>;
|
|
196
205
|
getRequestedActivation(request: ActivationRequestResponse): Promise<License | null>;
|
|
206
|
+
requestTrial(): Promise<License>;
|
|
197
207
|
validateLicense(license: License): Promise<License>;
|
|
198
208
|
validateRawLicense(rawLicense: Buffer): Promise<License>;
|
|
199
209
|
revokeLicense(license: License): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -83,6 +83,22 @@ var LicenseClient = class {
|
|
|
83
83
|
if (response.status === 204 || response.status === 404) return null;
|
|
84
84
|
return await this.handleLicenseResponse(response);
|
|
85
85
|
}
|
|
86
|
+
async requestTrial() {
|
|
87
|
+
const content = {
|
|
88
|
+
deviceName: await this.deviceIdResolver.resolveDeviceName(),
|
|
89
|
+
deviceSignature: await this.deviceIdResolver.resolveDeviceId()
|
|
90
|
+
};
|
|
91
|
+
const response = await fetch(this.configuration.endpoint + `/api/client/trials/${this.configuration.productId}/request?format=JWT`, {
|
|
92
|
+
...defaultFetchOptions,
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: {
|
|
95
|
+
...defaultFetchOptions.headers,
|
|
96
|
+
"Content-Type": "application/json"
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify(content)
|
|
99
|
+
});
|
|
100
|
+
return await this.handleLicenseResponse(response);
|
|
101
|
+
}
|
|
86
102
|
async validateLicense(license) {
|
|
87
103
|
const response = await fetch(this.configuration.endpoint + `/api/client/licenses/${this.configuration.productId}/validate?format=JWT`, {
|
|
88
104
|
...defaultFetchOptions,
|
package/package.json
CHANGED