intgate 1.0.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 ADDED
@@ -0,0 +1,325 @@
1
+ # IntGate Node.js/TypeScript Client Library
2
+
3
+ Node.js and TypeScript client library for the [IntGate](https://license.intserver.com) license verification API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install intgate
9
+ ```
10
+
11
+ Or with yarn:
12
+
13
+ ```bash
14
+ yarn add intgate
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ### TypeScript
20
+
21
+ ```typescript
22
+ import { IntGateClient } from 'intgate';
23
+
24
+ // Initialize the client with your team ID
25
+ const client = new IntGateClient('your-team-uuid-here');
26
+
27
+ // Verify a license
28
+ async function verifyLicense() {
29
+ try {
30
+ const result = await client.verifyLicense({
31
+ licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
32
+ hardwareIdentifier: 'unique-device-id',
33
+ version: '1.0.0'
34
+ });
35
+
36
+ if (result.result.valid) {
37
+ console.log('License is valid!');
38
+ console.log('License data:', result.data);
39
+ } else {
40
+ console.log('License invalid:', result.result.details);
41
+ }
42
+ } catch (error) {
43
+ console.error('Error:', error);
44
+ }
45
+ }
46
+
47
+ verifyLicense();
48
+ ```
49
+
50
+ ### JavaScript
51
+
52
+ ```javascript
53
+ const { IntGateClient } = require('intgate');
54
+
55
+ // Initialize the client with your team ID
56
+ const client = new IntGateClient('your-team-uuid-here');
57
+
58
+ // Verify a license
59
+ async function verifyLicense() {
60
+ try {
61
+ const result = await client.verifyLicense({
62
+ licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
63
+ hardwareIdentifier: 'unique-device-id',
64
+ version: '1.0.0'
65
+ });
66
+
67
+ if (result.result.valid) {
68
+ console.log('License is valid!');
69
+ }
70
+ } catch (error) {
71
+ console.error('Error:', error);
72
+ }
73
+ }
74
+ ```
75
+
76
+ ## API Reference
77
+
78
+ ### Initialize Client
79
+
80
+ ```typescript
81
+ import { IntGateClient } from 'intgate';
82
+
83
+ const client = new IntGateClient(
84
+ 'your-team-uuid', // Required: Your team's UUID from IntGate dashboard
85
+ 'https://license.intserver.com/api/v1' // Optional: Custom API base URL
86
+ );
87
+ ```
88
+
89
+ ### Verify License
90
+
91
+ Validates a license key and returns license information, customer data, and product details.
92
+
93
+ ```typescript
94
+ const result = await client.verifyLicense({
95
+ licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', // Required
96
+ customerId: 'customer-uuid', // Optional: Required if strict customers enabled
97
+ productId: 'product-uuid', // Optional: Required if strict products enabled
98
+ challenge: 'random-string', // Optional: For request signing
99
+ version: '1.0.0', // Optional: Software version (3-255 chars)
100
+ hardwareIdentifier: 'device-id', // Optional: Unique device ID (10-1000 chars)
101
+ branch: 'main' // Optional: Product branch (2-255 chars)
102
+ });
103
+ ```
104
+
105
+ ### License Heartbeat
106
+
107
+ Send periodic heartbeats to determine if a device is still active.
108
+
109
+ ```typescript
110
+ const result = await client.licenseHeartbeat({
111
+ licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', // Required
112
+ hardwareIdentifier: 'device-id', // Required: Unique device ID (10-1000 chars)
113
+ customerId: 'customer-uuid', // Optional
114
+ productId: 'product-uuid', // Optional
115
+ challenge: 'random-string', // Optional
116
+ version: '1.0.0', // Optional: Software version (3-255 chars)
117
+ branch: 'main' // Optional: Product branch (2-255 chars)
118
+ });
119
+ ```
120
+
121
+ ### Download Release
122
+
123
+ Download an encrypted release file.
124
+
125
+ ```typescript
126
+ const encryptedFile = await client.downloadRelease({
127
+ licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', // Required
128
+ productId: 'product-uuid', // Required
129
+ sessionKey: 'encrypted-session-key', // Required: Encrypted with team's public key
130
+ hardwareIdentifier: 'device-id', // Required: Unique device ID
131
+ version: '1.0.0', // Required: Software version
132
+ customerId: 'customer-uuid', // Optional
133
+ branch: 'main' // Optional: Product branch
134
+ });
135
+
136
+ // Save to file:
137
+ import fs from 'fs';
138
+ fs.writeFileSync('release.encrypted', encryptedFile);
139
+ ```
140
+
141
+ ## Automatic Heartbeat
142
+
143
+ Start automatic heartbeat in the background with event-based notifications.
144
+
145
+ ```typescript
146
+ import { IntGateClient } from 'intgate';
147
+
148
+ const client = new IntGateClient('your-team-uuid');
149
+
150
+ // Listen for heartbeat events
151
+ client.on('heartbeat', (result) => {
152
+ console.log(`✓ Heartbeat OK at ${result.result.timestamp}`);
153
+ console.log(` License valid: ${result.result.valid}`);
154
+ });
155
+
156
+ client.on('heartbeat-error', (error) => {
157
+ console.error('✗ Heartbeat failed:', error);
158
+ });
159
+
160
+ // Start automatic heartbeat (runs with setTimeout)
161
+ client.startAutomaticHeartbeat(
162
+ {
163
+ licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
164
+ hardwareIdentifier: 'device-12345',
165
+ version: '1.0.0'
166
+ },
167
+ 1800000 // 30 minutes in milliseconds
168
+ );
169
+
170
+ console.log('Application running with automatic heartbeat...');
171
+
172
+ // Get last heartbeat result anytime
173
+ const lastResult = client.getLastHeartbeatResult();
174
+ if (lastResult?.result.valid) {
175
+ console.log('License is active');
176
+ }
177
+
178
+ // Check if heartbeat is running
179
+ if (client.isHeartbeatRunning()) {
180
+ console.log('Automatic heartbeat is active');
181
+ }
182
+
183
+ // Stop when done
184
+ client.stopAutomaticHeartbeat();
185
+ ```
186
+
187
+ ## Error Handling
188
+
189
+ The library provides specific exception types:
190
+
191
+ ```typescript
192
+ import {
193
+ IntGateClient,
194
+ IntGateAPIError,
195
+ IntGateValidationError
196
+ } from 'intgate';
197
+
198
+ const client = new IntGateClient('your-team-uuid');
199
+
200
+ try {
201
+ const result = await client.verifyLicense({
202
+ licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX'
203
+ });
204
+ } catch (error) {
205
+ if (error instanceof IntGateValidationError) {
206
+ // Input validation failed
207
+ console.error('Validation error:', error.message);
208
+ } else if (error instanceof IntGateAPIError) {
209
+ // API request failed
210
+ console.error('API error:', error.message);
211
+ console.error('Status code:', error.statusCode);
212
+ console.error('Response data:', error.responseData);
213
+ } else {
214
+ // Other errors
215
+ console.error('Unexpected error:', error);
216
+ }
217
+ }
218
+ ```
219
+
220
+ ## Complete Example
221
+
222
+ ```typescript
223
+ import { IntGateClient, IntGateAPIError } from 'intgate';
224
+
225
+ // Initialize client
226
+ const client = new IntGateClient('your-team-uuid-here');
227
+
228
+ async function main() {
229
+ try {
230
+ // Verify license on startup
231
+ console.log('Verifying license...');
232
+ const result = await client.verifyLicense({
233
+ licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
234
+ hardwareIdentifier: 'my-device-12345',
235
+ version: '1.0.0',
236
+ productId: 'your-product-uuid'
237
+ });
238
+
239
+ if (!result.result.valid) {
240
+ console.error('License validation failed:', result.result.details);
241
+ process.exit(1);
242
+ }
243
+
244
+ console.log('License verified successfully!');
245
+ console.log('Expires:', result.data.license.expirationDate || 'Never');
246
+
247
+ // Setup automatic heartbeat with event listeners
248
+ console.log('\nStarting automatic heartbeat...');
249
+
250
+ client.on('heartbeat', (result) => {
251
+ console.log('Heartbeat successful');
252
+ });
253
+
254
+ client.on('heartbeat-error', (error) => {
255
+ console.error('Heartbeat failed:', error);
256
+ });
257
+
258
+ client.startAutomaticHeartbeat(
259
+ {
260
+ licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
261
+ hardwareIdentifier: 'my-device-12345',
262
+ version: '1.0.0'
263
+ },
264
+ 1800000 // Every 30 minutes
265
+ );
266
+
267
+ console.log('Application running...');
268
+
269
+ } catch (error) {
270
+ if (error instanceof IntGateAPIError) {
271
+ console.error('API Error:', error.message);
272
+ if (error.statusCode === 404) {
273
+ console.error('License not found');
274
+ } else if (error.statusCode === 401) {
275
+ console.error('Unauthorized - check your team ID');
276
+ }
277
+ process.exit(1);
278
+ }
279
+ throw error;
280
+ }
281
+ }
282
+
283
+ main();
284
+ ```
285
+
286
+ ## TypeScript Support
287
+
288
+ This library is written in TypeScript and includes full type definitions:
289
+
290
+ ```typescript
291
+ import {
292
+ IntGateClient,
293
+ VerifyLicenseOptions,
294
+ VerifyLicenseResponse,
295
+ LicenseHeartbeatOptions,
296
+ HeartbeatResponse,
297
+ DownloadReleaseOptions,
298
+ License,
299
+ Customer,
300
+ Product,
301
+ VerificationResult
302
+ } from 'intgate';
303
+ ```
304
+
305
+ ## Build from Source
306
+
307
+ ```bash
308
+ # Install dependencies
309
+ npm install
310
+
311
+ # Build TypeScript to JavaScript
312
+ npm run build
313
+
314
+ # The built files will be in the dist/ directory
315
+ ```
316
+
317
+ ## License
318
+
319
+ MIT License
320
+
321
+ ## Support
322
+
323
+ For API documentation, visit: https://license.intserver.com
324
+
325
+ For examples, see: [AUTOMATIC_HEARTBEAT.md](../AUTOMATIC_HEARTBEAT.md)
@@ -0,0 +1,103 @@
1
+ /**
2
+ * IntGate API Client implementation for Node.js/TypeScript.
3
+ */
4
+ import { EventEmitter } from 'events';
5
+ import { VerifyLicenseOptions, LicenseHeartbeatOptions, DownloadReleaseOptions, VerifyLicenseResponse, HeartbeatResponse } from './types';
6
+ /**
7
+ * Client for interacting with the IntGate license verification API.
8
+ */
9
+ export declare class IntGateClient extends EventEmitter {
10
+ private teamId;
11
+ private baseUrl;
12
+ private axiosInstance;
13
+ private heartbeatTimer;
14
+ private heartbeatRunning;
15
+ private lastHeartbeatResult;
16
+ /**
17
+ * Initialize the IntGate client.
18
+ * @param teamId Your team's UUID from the IntGate dashboard.
19
+ * @param baseUrl The base URL for the IntGate API (default: https://license.intserver.com/api/v1).
20
+ */
21
+ constructor(teamId: string, baseUrl?: string);
22
+ /**
23
+ * Verify a license key with the IntGate backend.
24
+ *
25
+ * This endpoint validates a license key and returns license information,
26
+ * customer data, and product details. Typically called when software starts.
27
+ *
28
+ * @param options License verification options
29
+ * @returns Promise resolving to verification response
30
+ * @throws {IntGateValidationError} If required parameters are invalid
31
+ * @throws {IntGateAPIError} If the API request fails
32
+ */
33
+ verifyLicense(options: VerifyLicenseOptions): Promise<VerifyLicenseResponse>;
34
+ /**
35
+ * Send a heartbeat to determine if a device is still active.
36
+ *
37
+ * This endpoint should be called at regular intervals (e.g., every 30 minutes).
38
+ * It validates the license key similar to verifyLicense.
39
+ *
40
+ * @param options Heartbeat options
41
+ * @returns Promise resolving to heartbeat response
42
+ * @throws {IntGateValidationError} If required parameters are invalid
43
+ * @throws {IntGateAPIError} If the API request fails
44
+ */
45
+ licenseHeartbeat(options: LicenseHeartbeatOptions): Promise<HeartbeatResponse>;
46
+ /**
47
+ * Download an encrypted release file.
48
+ *
49
+ * This endpoint is primarily for languages that support loading code remotely
50
+ * (e.g., Java classloaders). The file is encrypted using the provided session key.
51
+ *
52
+ * @param options Download release options
53
+ * @returns Promise resolving to encrypted file content (Buffer)
54
+ * @throws {IntGateValidationError} If required parameters are invalid
55
+ * @throws {IntGateAPIError} If the API request fails
56
+ */
57
+ downloadRelease(options: DownloadReleaseOptions): Promise<Buffer>;
58
+ /**
59
+ * Start automatic heartbeat in the background.
60
+ *
61
+ * The client will emit 'heartbeat' events with the result on success,
62
+ * and 'heartbeat-error' events on errors.
63
+ *
64
+ * @param options Heartbeat options
65
+ * @param interval Interval in milliseconds between heartbeats (default: 1800000 = 30 minutes)
66
+ *
67
+ * @example
68
+ * client.startAutomaticHeartbeat({
69
+ * licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
70
+ * hardwareIdentifier: 'device-123'
71
+ * }, 60000); // Every 1 minute
72
+ *
73
+ * client.on('heartbeat', (result) => {
74
+ * console.log('Heartbeat successful:', result);
75
+ * });
76
+ *
77
+ * client.on('heartbeat-error', (error) => {
78
+ * console.error('Heartbeat failed:', error);
79
+ * });
80
+ */
81
+ startAutomaticHeartbeat(options: LicenseHeartbeatOptions, interval?: number): void;
82
+ /**
83
+ * Stop the automatic heartbeat.
84
+ */
85
+ stopAutomaticHeartbeat(): void;
86
+ /**
87
+ * Get the result of the last automatic heartbeat.
88
+ *
89
+ * @returns The last heartbeat result, or null if no heartbeat has run yet
90
+ */
91
+ getLastHeartbeatResult(): HeartbeatResponse | null;
92
+ /**
93
+ * Check if automatic heartbeat is currently running.
94
+ *
95
+ * @returns True if heartbeat is running, false otherwise
96
+ */
97
+ isHeartbeatRunning(): boolean;
98
+ /**
99
+ * Handle errors from API requests.
100
+ * @private
101
+ */
102
+ private handleError;
103
+ }
package/dist/client.js ADDED
@@ -0,0 +1,252 @@
1
+ "use strict";
2
+ /**
3
+ * IntGate API Client implementation for Node.js/TypeScript.
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.IntGateClient = void 0;
10
+ const axios_1 = __importDefault(require("axios"));
11
+ const events_1 = require("events");
12
+ const exceptions_1 = require("./exceptions");
13
+ /**
14
+ * Client for interacting with the IntGate license verification API.
15
+ */
16
+ class IntGateClient extends events_1.EventEmitter {
17
+ /**
18
+ * Initialize the IntGate client.
19
+ * @param teamId Your team's UUID from the IntGate dashboard.
20
+ * @param baseUrl The base URL for the IntGate API (default: https://license.intserver.com/api/v1).
21
+ */
22
+ constructor(teamId, baseUrl = 'https://license.intserver.com/api/v1') {
23
+ super();
24
+ this.heartbeatTimer = null;
25
+ this.heartbeatRunning = false;
26
+ this.lastHeartbeatResult = null;
27
+ if (!teamId) {
28
+ throw new exceptions_1.IntGateValidationError('teamId is required');
29
+ }
30
+ this.teamId = teamId;
31
+ this.baseUrl = baseUrl.replace(/\/$/, '');
32
+ this.axiosInstance = axios_1.default.create({
33
+ headers: {
34
+ 'Content-Type': 'application/json',
35
+ },
36
+ });
37
+ }
38
+ /**
39
+ * Verify a license key with the IntGate backend.
40
+ *
41
+ * This endpoint validates a license key and returns license information,
42
+ * customer data, and product details. Typically called when software starts.
43
+ *
44
+ * @param options License verification options
45
+ * @returns Promise resolving to verification response
46
+ * @throws {IntGateValidationError} If required parameters are invalid
47
+ * @throws {IntGateAPIError} If the API request fails
48
+ */
49
+ async verifyLicense(options) {
50
+ if (!options.licenseKey) {
51
+ throw new exceptions_1.IntGateValidationError('licenseKey is required');
52
+ }
53
+ const payload = {
54
+ licenseKey: options.licenseKey,
55
+ };
56
+ if (options.customerId)
57
+ payload.customerId = options.customerId;
58
+ if (options.productId)
59
+ payload.productId = options.productId;
60
+ if (options.challenge)
61
+ payload.challenge = options.challenge;
62
+ if (options.version)
63
+ payload.version = options.version;
64
+ if (options.hardwareIdentifier)
65
+ payload.hardwareIdentifier = options.hardwareIdentifier;
66
+ if (options.branch)
67
+ payload.branch = options.branch;
68
+ const url = `${this.baseUrl}/client/teams/${this.teamId}/verification/verify`;
69
+ try {
70
+ const response = await this.axiosInstance.post(url, payload);
71
+ return response.data;
72
+ }
73
+ catch (error) {
74
+ this.handleError(error);
75
+ }
76
+ }
77
+ /**
78
+ * Send a heartbeat to determine if a device is still active.
79
+ *
80
+ * This endpoint should be called at regular intervals (e.g., every 30 minutes).
81
+ * It validates the license key similar to verifyLicense.
82
+ *
83
+ * @param options Heartbeat options
84
+ * @returns Promise resolving to heartbeat response
85
+ * @throws {IntGateValidationError} If required parameters are invalid
86
+ * @throws {IntGateAPIError} If the API request fails
87
+ */
88
+ async licenseHeartbeat(options) {
89
+ if (!options.licenseKey) {
90
+ throw new exceptions_1.IntGateValidationError('licenseKey is required');
91
+ }
92
+ if (!options.hardwareIdentifier) {
93
+ throw new exceptions_1.IntGateValidationError('hardwareIdentifier is required');
94
+ }
95
+ const payload = {
96
+ licenseKey: options.licenseKey,
97
+ hardwareIdentifier: options.hardwareIdentifier,
98
+ };
99
+ if (options.customerId)
100
+ payload.customerId = options.customerId;
101
+ if (options.productId)
102
+ payload.productId = options.productId;
103
+ if (options.challenge)
104
+ payload.challenge = options.challenge;
105
+ if (options.version)
106
+ payload.version = options.version;
107
+ if (options.branch)
108
+ payload.branch = options.branch;
109
+ const url = `${this.baseUrl}/client/teams/${this.teamId}/verification/heartbeat`;
110
+ try {
111
+ const response = await this.axiosInstance.post(url, payload);
112
+ return response.data;
113
+ }
114
+ catch (error) {
115
+ this.handleError(error);
116
+ }
117
+ }
118
+ /**
119
+ * Download an encrypted release file.
120
+ *
121
+ * This endpoint is primarily for languages that support loading code remotely
122
+ * (e.g., Java classloaders). The file is encrypted using the provided session key.
123
+ *
124
+ * @param options Download release options
125
+ * @returns Promise resolving to encrypted file content (Buffer)
126
+ * @throws {IntGateValidationError} If required parameters are invalid
127
+ * @throws {IntGateAPIError} If the API request fails
128
+ */
129
+ async downloadRelease(options) {
130
+ if (!options.licenseKey) {
131
+ throw new exceptions_1.IntGateValidationError('licenseKey is required');
132
+ }
133
+ if (!options.productId) {
134
+ throw new exceptions_1.IntGateValidationError('productId is required');
135
+ }
136
+ if (!options.sessionKey) {
137
+ throw new exceptions_1.IntGateValidationError('sessionKey is required');
138
+ }
139
+ if (!options.hardwareIdentifier) {
140
+ throw new exceptions_1.IntGateValidationError('hardwareIdentifier is required');
141
+ }
142
+ if (!options.version) {
143
+ throw new exceptions_1.IntGateValidationError('version is required');
144
+ }
145
+ const params = {
146
+ licenseKey: options.licenseKey,
147
+ productId: options.productId,
148
+ sessionKey: options.sessionKey,
149
+ hardwareIdentifier: options.hardwareIdentifier,
150
+ version: options.version,
151
+ };
152
+ if (options.customerId)
153
+ params.customerId = options.customerId;
154
+ if (options.branch)
155
+ params.branch = options.branch;
156
+ const url = `${this.baseUrl}/client/teams/${this.teamId}/verification/classloader`;
157
+ try {
158
+ const response = await this.axiosInstance.get(url, {
159
+ params,
160
+ responseType: 'arraybuffer',
161
+ });
162
+ return Buffer.from(response.data);
163
+ }
164
+ catch (error) {
165
+ this.handleError(error);
166
+ }
167
+ }
168
+ /**
169
+ * Start automatic heartbeat in the background.
170
+ *
171
+ * The client will emit 'heartbeat' events with the result on success,
172
+ * and 'heartbeat-error' events on errors.
173
+ *
174
+ * @param options Heartbeat options
175
+ * @param interval Interval in milliseconds between heartbeats (default: 1800000 = 30 minutes)
176
+ *
177
+ * @example
178
+ * client.startAutomaticHeartbeat({
179
+ * licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
180
+ * hardwareIdentifier: 'device-123'
181
+ * }, 60000); // Every 1 minute
182
+ *
183
+ * client.on('heartbeat', (result) => {
184
+ * console.log('Heartbeat successful:', result);
185
+ * });
186
+ *
187
+ * client.on('heartbeat-error', (error) => {
188
+ * console.error('Heartbeat failed:', error);
189
+ * });
190
+ */
191
+ startAutomaticHeartbeat(options, interval = 1800000) {
192
+ if (this.heartbeatRunning) {
193
+ throw new exceptions_1.IntGateValidationError('Automatic heartbeat is already running');
194
+ }
195
+ this.heartbeatRunning = true;
196
+ const runHeartbeat = async () => {
197
+ try {
198
+ const result = await this.licenseHeartbeat(options);
199
+ this.lastHeartbeatResult = result;
200
+ this.emit('heartbeat', result);
201
+ }
202
+ catch (error) {
203
+ this.emit('heartbeat-error', error);
204
+ }
205
+ if (this.heartbeatRunning) {
206
+ this.heartbeatTimer = setTimeout(runHeartbeat, interval);
207
+ }
208
+ };
209
+ // Run immediately, then schedule
210
+ runHeartbeat();
211
+ }
212
+ /**
213
+ * Stop the automatic heartbeat.
214
+ */
215
+ stopAutomaticHeartbeat() {
216
+ this.heartbeatRunning = false;
217
+ if (this.heartbeatTimer) {
218
+ clearTimeout(this.heartbeatTimer);
219
+ this.heartbeatTimer = null;
220
+ }
221
+ }
222
+ /**
223
+ * Get the result of the last automatic heartbeat.
224
+ *
225
+ * @returns The last heartbeat result, or null if no heartbeat has run yet
226
+ */
227
+ getLastHeartbeatResult() {
228
+ return this.lastHeartbeatResult;
229
+ }
230
+ /**
231
+ * Check if automatic heartbeat is currently running.
232
+ *
233
+ * @returns True if heartbeat is running, false otherwise
234
+ */
235
+ isHeartbeatRunning() {
236
+ return this.heartbeatRunning;
237
+ }
238
+ /**
239
+ * Handle errors from API requests.
240
+ * @private
241
+ */
242
+ handleError(error) {
243
+ if (axios_1.default.isAxiosError(error)) {
244
+ const axiosError = error;
245
+ const statusCode = axiosError.response?.status;
246
+ const responseData = axiosError.response?.data;
247
+ throw new exceptions_1.IntGateAPIError(`API request failed: ${axiosError.message}`, statusCode, responseData);
248
+ }
249
+ throw new exceptions_1.IntGateAPIError(`Network error: ${error.message}`);
250
+ }
251
+ }
252
+ exports.IntGateClient = IntGateClient;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Custom error classes for the IntGate API client.
3
+ */
4
+ /**
5
+ * Base error class for all IntGate errors.
6
+ */
7
+ export declare class IntGateError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ /**
11
+ * Error thrown when the API returns an error response.
12
+ */
13
+ export declare class IntGateAPIError extends IntGateError {
14
+ statusCode?: number;
15
+ responseData?: any;
16
+ constructor(message: string, statusCode?: number, responseData?: any);
17
+ }
18
+ /**
19
+ * Error thrown when input validation fails.
20
+ */
21
+ export declare class IntGateValidationError extends IntGateError {
22
+ constructor(message: string);
23
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ /**
3
+ * Custom error classes for the IntGate API client.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.IntGateValidationError = exports.IntGateAPIError = exports.IntGateError = void 0;
7
+ /**
8
+ * Base error class for all IntGate errors.
9
+ */
10
+ class IntGateError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = 'IntGateError';
14
+ Object.setPrototypeOf(this, IntGateError.prototype);
15
+ }
16
+ }
17
+ exports.IntGateError = IntGateError;
18
+ /**
19
+ * Error thrown when the API returns an error response.
20
+ */
21
+ class IntGateAPIError extends IntGateError {
22
+ constructor(message, statusCode, responseData) {
23
+ super(message);
24
+ this.name = 'IntGateAPIError';
25
+ this.statusCode = statusCode;
26
+ this.responseData = responseData;
27
+ Object.setPrototypeOf(this, IntGateAPIError.prototype);
28
+ }
29
+ }
30
+ exports.IntGateAPIError = IntGateAPIError;
31
+ /**
32
+ * Error thrown when input validation fails.
33
+ */
34
+ class IntGateValidationError extends IntGateError {
35
+ constructor(message) {
36
+ super(message);
37
+ this.name = 'IntGateValidationError';
38
+ Object.setPrototypeOf(this, IntGateValidationError.prototype);
39
+ }
40
+ }
41
+ exports.IntGateValidationError = IntGateValidationError;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * IntGate API Client Library for Node.js/TypeScript
3
+ * A Node.js/TypeScript client library for the IntGate license verification API.
4
+ */
5
+ export { IntGateClient } from './client';
6
+ export { IntGateError, IntGateAPIError, IntGateValidationError } from './exceptions';
7
+ export * from './types';
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * IntGate API Client Library for Node.js/TypeScript
4
+ * A Node.js/TypeScript client library for the IntGate license verification API.
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.IntGateValidationError = exports.IntGateAPIError = exports.IntGateError = exports.IntGateClient = void 0;
22
+ var client_1 = require("./client");
23
+ Object.defineProperty(exports, "IntGateClient", { enumerable: true, get: function () { return client_1.IntGateClient; } });
24
+ var exceptions_1 = require("./exceptions");
25
+ Object.defineProperty(exports, "IntGateError", { enumerable: true, get: function () { return exceptions_1.IntGateError; } });
26
+ Object.defineProperty(exports, "IntGateAPIError", { enumerable: true, get: function () { return exceptions_1.IntGateAPIError; } });
27
+ Object.defineProperty(exports, "IntGateValidationError", { enumerable: true, get: function () { return exceptions_1.IntGateValidationError; } });
28
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Type definitions for the Lukittu API client.
3
+ */
4
+ export interface LicenseMetadata {
5
+ key: string;
6
+ value: string;
7
+ }
8
+ export interface License {
9
+ ipLimit: number;
10
+ hwidLimit: number;
11
+ expirationType: 'NEVER' | 'DATE' | 'DAYS';
12
+ expirationStart?: 'CREATION' | 'ACTIVATION';
13
+ expirationDate?: string;
14
+ expirationDays?: number;
15
+ metadata?: LicenseMetadata[];
16
+ }
17
+ export interface Customer {
18
+ email: string;
19
+ fullName: string;
20
+ username: string;
21
+ metadata?: LicenseMetadata[];
22
+ }
23
+ export interface LatestRelease {
24
+ version: string;
25
+ createdAt: string;
26
+ }
27
+ export interface Product {
28
+ name: string;
29
+ url: string;
30
+ latestRelease?: LatestRelease;
31
+ metadata?: LicenseMetadata[];
32
+ }
33
+ export interface VerificationResult {
34
+ timestamp: string;
35
+ valid: boolean;
36
+ details: string;
37
+ code: string;
38
+ challengeResponse?: string;
39
+ }
40
+ export interface VerifyLicenseResponse {
41
+ data: {
42
+ license: License;
43
+ customers: Customer[];
44
+ products: Product[];
45
+ };
46
+ result: VerificationResult;
47
+ }
48
+ export interface HeartbeatResponse {
49
+ data: {
50
+ license: {
51
+ ipLimit: number;
52
+ hwidLimit: number;
53
+ expirationType: string;
54
+ };
55
+ };
56
+ result: VerificationResult;
57
+ }
58
+ export interface VerifyLicenseOptions {
59
+ licenseKey: string;
60
+ customerId?: string;
61
+ productId?: string;
62
+ challenge?: string;
63
+ version?: string;
64
+ hardwareIdentifier?: string;
65
+ branch?: string;
66
+ }
67
+ export interface LicenseHeartbeatOptions {
68
+ licenseKey: string;
69
+ hardwareIdentifier: string;
70
+ customerId?: string;
71
+ productId?: string;
72
+ challenge?: string;
73
+ version?: string;
74
+ branch?: string;
75
+ }
76
+ export interface DownloadReleaseOptions {
77
+ licenseKey: string;
78
+ productId: string;
79
+ sessionKey: string;
80
+ hardwareIdentifier: string;
81
+ version: string;
82
+ customerId?: string;
83
+ branch?: string;
84
+ }
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * Type definitions for the Lukittu API client.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "intgate",
3
+ "version": "1.0.0",
4
+ "description": "Node.js client library for the IntGate license verification API",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "prepare": "npm run build"
10
+ },
11
+ "keywords": [
12
+ "intgate",
13
+ "license",
14
+ "verification",
15
+ "api",
16
+ "client"
17
+ ],
18
+ "author": "IntGate Client Library",
19
+ "license": "MIT",
20
+ "dependencies": {
21
+ "axios": "^1.6.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.0.0",
25
+ "typescript": "^5.0.0"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/intgate/intgate-nodejs"
30
+ },
31
+ "homepage": "https://license.intserver.com"
32
+ }
package/src/client.ts ADDED
@@ -0,0 +1,272 @@
1
+ /**
2
+ * IntGate API Client implementation for Node.js/TypeScript.
3
+ */
4
+
5
+ import axios, { AxiosInstance, AxiosError } from 'axios';
6
+ import { EventEmitter } from 'events';
7
+ import { IntGateAPIError, IntGateValidationError } from './exceptions';
8
+ import {
9
+ VerifyLicenseOptions,
10
+ LicenseHeartbeatOptions,
11
+ DownloadReleaseOptions,
12
+ VerifyLicenseResponse,
13
+ HeartbeatResponse,
14
+ } from './types';
15
+
16
+ /**
17
+ * Client for interacting with the IntGate license verification API.
18
+ */
19
+ export class IntGateClient extends EventEmitter {
20
+ private teamId: string;
21
+ private baseUrl: string;
22
+ private axiosInstance: AxiosInstance;
23
+ private heartbeatTimer: NodeJS.Timeout | null = null;
24
+ private heartbeatRunning: boolean = false;
25
+ private lastHeartbeatResult: HeartbeatResponse | null = null;
26
+
27
+ /**
28
+ * Initialize the IntGate client.
29
+ * @param teamId Your team's UUID from the IntGate dashboard.
30
+ * @param baseUrl The base URL for the IntGate API (default: https://license.intserver.com/api/v1).
31
+ */
32
+ constructor(teamId: string, baseUrl: string = 'https://license.intserver.com/api/v1') {
33
+ super();
34
+
35
+ if (!teamId) {
36
+ throw new IntGateValidationError('teamId is required');
37
+ }
38
+
39
+ this.teamId = teamId;
40
+ this.baseUrl = baseUrl.replace(/\/$/, '');
41
+ this.axiosInstance = axios.create({
42
+ headers: {
43
+ 'Content-Type': 'application/json',
44
+ },
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Verify a license key with the IntGate backend.
50
+ *
51
+ * This endpoint validates a license key and returns license information,
52
+ * customer data, and product details. Typically called when software starts.
53
+ *
54
+ * @param options License verification options
55
+ * @returns Promise resolving to verification response
56
+ * @throws {IntGateValidationError} If required parameters are invalid
57
+ * @throws {IntGateAPIError} If the API request fails
58
+ */
59
+ async verifyLicense(options: VerifyLicenseOptions): Promise<VerifyLicenseResponse> {
60
+ if (!options.licenseKey) {
61
+ throw new IntGateValidationError('licenseKey is required');
62
+ }
63
+
64
+ const payload: any = {
65
+ licenseKey: options.licenseKey,
66
+ };
67
+
68
+ if (options.customerId) payload.customerId = options.customerId;
69
+ if (options.productId) payload.productId = options.productId;
70
+ if (options.challenge) payload.challenge = options.challenge;
71
+ if (options.version) payload.version = options.version;
72
+ if (options.hardwareIdentifier) payload.hardwareIdentifier = options.hardwareIdentifier;
73
+ if (options.branch) payload.branch = options.branch;
74
+
75
+ const url = `${this.baseUrl}/client/teams/${this.teamId}/verification/verify`;
76
+
77
+ try {
78
+ const response = await this.axiosInstance.post<VerifyLicenseResponse>(url, payload);
79
+ return response.data;
80
+ } catch (error) {
81
+ this.handleError(error);
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Send a heartbeat to determine if a device is still active.
87
+ *
88
+ * This endpoint should be called at regular intervals (e.g., every 30 minutes).
89
+ * It validates the license key similar to verifyLicense.
90
+ *
91
+ * @param options Heartbeat options
92
+ * @returns Promise resolving to heartbeat response
93
+ * @throws {IntGateValidationError} If required parameters are invalid
94
+ * @throws {IntGateAPIError} If the API request fails
95
+ */
96
+ async licenseHeartbeat(options: LicenseHeartbeatOptions): Promise<HeartbeatResponse> {
97
+ if (!options.licenseKey) {
98
+ throw new IntGateValidationError('licenseKey is required');
99
+ }
100
+ if (!options.hardwareIdentifier) {
101
+ throw new IntGateValidationError('hardwareIdentifier is required');
102
+ }
103
+
104
+ const payload: any = {
105
+ licenseKey: options.licenseKey,
106
+ hardwareIdentifier: options.hardwareIdentifier,
107
+ };
108
+
109
+ if (options.customerId) payload.customerId = options.customerId;
110
+ if (options.productId) payload.productId = options.productId;
111
+ if (options.challenge) payload.challenge = options.challenge;
112
+ if (options.version) payload.version = options.version;
113
+ if (options.branch) payload.branch = options.branch;
114
+
115
+ const url = `${this.baseUrl}/client/teams/${this.teamId}/verification/heartbeat`;
116
+
117
+ try {
118
+ const response = await this.axiosInstance.post<HeartbeatResponse>(url, payload);
119
+ return response.data;
120
+ } catch (error) {
121
+ this.handleError(error);
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Download an encrypted release file.
127
+ *
128
+ * This endpoint is primarily for languages that support loading code remotely
129
+ * (e.g., Java classloaders). The file is encrypted using the provided session key.
130
+ *
131
+ * @param options Download release options
132
+ * @returns Promise resolving to encrypted file content (Buffer)
133
+ * @throws {IntGateValidationError} If required parameters are invalid
134
+ * @throws {IntGateAPIError} If the API request fails
135
+ */
136
+ async downloadRelease(options: DownloadReleaseOptions): Promise<Buffer> {
137
+ if (!options.licenseKey) {
138
+ throw new IntGateValidationError('licenseKey is required');
139
+ }
140
+ if (!options.productId) {
141
+ throw new IntGateValidationError('productId is required');
142
+ }
143
+ if (!options.sessionKey) {
144
+ throw new IntGateValidationError('sessionKey is required');
145
+ }
146
+ if (!options.hardwareIdentifier) {
147
+ throw new IntGateValidationError('hardwareIdentifier is required');
148
+ }
149
+ if (!options.version) {
150
+ throw new IntGateValidationError('version is required');
151
+ }
152
+
153
+ const params: any = {
154
+ licenseKey: options.licenseKey,
155
+ productId: options.productId,
156
+ sessionKey: options.sessionKey,
157
+ hardwareIdentifier: options.hardwareIdentifier,
158
+ version: options.version,
159
+ };
160
+
161
+ if (options.customerId) params.customerId = options.customerId;
162
+ if (options.branch) params.branch = options.branch;
163
+
164
+ const url = `${this.baseUrl}/client/teams/${this.teamId}/verification/classloader`;
165
+
166
+ try {
167
+ const response = await this.axiosInstance.get(url, {
168
+ params,
169
+ responseType: 'arraybuffer',
170
+ });
171
+ return Buffer.from(response.data);
172
+ } catch (error) {
173
+ this.handleError(error);
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Start automatic heartbeat in the background.
179
+ *
180
+ * The client will emit 'heartbeat' events with the result on success,
181
+ * and 'heartbeat-error' events on errors.
182
+ *
183
+ * @param options Heartbeat options
184
+ * @param interval Interval in milliseconds between heartbeats (default: 1800000 = 30 minutes)
185
+ *
186
+ * @example
187
+ * client.startAutomaticHeartbeat({
188
+ * licenseKey: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',
189
+ * hardwareIdentifier: 'device-123'
190
+ * }, 60000); // Every 1 minute
191
+ *
192
+ * client.on('heartbeat', (result) => {
193
+ * console.log('Heartbeat successful:', result);
194
+ * });
195
+ *
196
+ * client.on('heartbeat-error', (error) => {
197
+ * console.error('Heartbeat failed:', error);
198
+ * });
199
+ */
200
+ startAutomaticHeartbeat(options: LicenseHeartbeatOptions, interval: number = 1800000): void {
201
+ if (this.heartbeatRunning) {
202
+ throw new IntGateValidationError('Automatic heartbeat is already running');
203
+ }
204
+
205
+ this.heartbeatRunning = true;
206
+
207
+ const runHeartbeat = async () => {
208
+ try {
209
+ const result = await this.licenseHeartbeat(options);
210
+ this.lastHeartbeatResult = result;
211
+ this.emit('heartbeat', result);
212
+ } catch (error) {
213
+ this.emit('heartbeat-error', error);
214
+ }
215
+
216
+ if (this.heartbeatRunning) {
217
+ this.heartbeatTimer = setTimeout(runHeartbeat, interval);
218
+ }
219
+ };
220
+
221
+ // Run immediately, then schedule
222
+ runHeartbeat();
223
+ }
224
+
225
+ /**
226
+ * Stop the automatic heartbeat.
227
+ */
228
+ stopAutomaticHeartbeat(): void {
229
+ this.heartbeatRunning = false;
230
+ if (this.heartbeatTimer) {
231
+ clearTimeout(this.heartbeatTimer);
232
+ this.heartbeatTimer = null;
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Get the result of the last automatic heartbeat.
238
+ *
239
+ * @returns The last heartbeat result, or null if no heartbeat has run yet
240
+ */
241
+ getLastHeartbeatResult(): HeartbeatResponse | null {
242
+ return this.lastHeartbeatResult;
243
+ }
244
+
245
+ /**
246
+ * Check if automatic heartbeat is currently running.
247
+ *
248
+ * @returns True if heartbeat is running, false otherwise
249
+ */
250
+ isHeartbeatRunning(): boolean {
251
+ return this.heartbeatRunning;
252
+ }
253
+
254
+ /**
255
+ * Handle errors from API requests.
256
+ * @private
257
+ */
258
+ private handleError(error: any): never {
259
+ if (axios.isAxiosError(error)) {
260
+ const axiosError = error as AxiosError;
261
+ const statusCode = axiosError.response?.status;
262
+ const responseData = axiosError.response?.data;
263
+
264
+ throw new IntGateAPIError(
265
+ `API request failed: ${axiosError.message}`,
266
+ statusCode,
267
+ responseData
268
+ );
269
+ }
270
+ throw new IntGateAPIError(`Network error: ${error.message}`);
271
+ }
272
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Custom error classes for the IntGate API client.
3
+ */
4
+
5
+ /**
6
+ * Base error class for all IntGate errors.
7
+ */
8
+ export class IntGateError extends Error {
9
+ constructor(message: string) {
10
+ super(message);
11
+ this.name = 'IntGateError';
12
+ Object.setPrototypeOf(this, IntGateError.prototype);
13
+ }
14
+ }
15
+
16
+ /**
17
+ * Error thrown when the API returns an error response.
18
+ */
19
+ export class IntGateAPIError extends IntGateError {
20
+ statusCode?: number;
21
+ responseData?: any;
22
+
23
+ constructor(message: string, statusCode?: number, responseData?: any) {
24
+ super(message);
25
+ this.name = 'IntGateAPIError';
26
+ this.statusCode = statusCode;
27
+ this.responseData = responseData;
28
+ Object.setPrototypeOf(this, IntGateAPIError.prototype);
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Error thrown when input validation fails.
34
+ */
35
+ export class IntGateValidationError extends IntGateError {
36
+ constructor(message: string) {
37
+ super(message);
38
+ this.name = 'IntGateValidationError';
39
+ Object.setPrototypeOf(this, IntGateValidationError.prototype);
40
+ }
41
+ }
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * IntGate API Client Library for Node.js/TypeScript
3
+ * A Node.js/TypeScript client library for the IntGate license verification API.
4
+ */
5
+
6
+ export { IntGateClient } from './client';
7
+ export { IntGateError, IntGateAPIError, IntGateValidationError } from './exceptions';
8
+ export * from './types';
package/src/types.ts ADDED
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Type definitions for the Lukittu API client.
3
+ */
4
+
5
+ export interface LicenseMetadata {
6
+ key: string;
7
+ value: string;
8
+ }
9
+
10
+ export interface License {
11
+ ipLimit: number;
12
+ hwidLimit: number;
13
+ expirationType: 'NEVER' | 'DATE' | 'DAYS';
14
+ expirationStart?: 'CREATION' | 'ACTIVATION';
15
+ expirationDate?: string;
16
+ expirationDays?: number;
17
+ metadata?: LicenseMetadata[];
18
+ }
19
+
20
+ export interface Customer {
21
+ email: string;
22
+ fullName: string;
23
+ username: string;
24
+ metadata?: LicenseMetadata[];
25
+ }
26
+
27
+ export interface LatestRelease {
28
+ version: string;
29
+ createdAt: string;
30
+ }
31
+
32
+ export interface Product {
33
+ name: string;
34
+ url: string;
35
+ latestRelease?: LatestRelease;
36
+ metadata?: LicenseMetadata[];
37
+ }
38
+
39
+ export interface VerificationResult {
40
+ timestamp: string;
41
+ valid: boolean;
42
+ details: string;
43
+ code: string;
44
+ challengeResponse?: string;
45
+ }
46
+
47
+ export interface VerifyLicenseResponse {
48
+ data: {
49
+ license: License;
50
+ customers: Customer[];
51
+ products: Product[];
52
+ };
53
+ result: VerificationResult;
54
+ }
55
+
56
+ export interface HeartbeatResponse {
57
+ data: {
58
+ license: {
59
+ ipLimit: number;
60
+ hwidLimit: number;
61
+ expirationType: string;
62
+ };
63
+ };
64
+ result: VerificationResult;
65
+ }
66
+
67
+ export interface VerifyLicenseOptions {
68
+ licenseKey: string;
69
+ customerId?: string;
70
+ productId?: string;
71
+ challenge?: string;
72
+ version?: string;
73
+ hardwareIdentifier?: string;
74
+ branch?: string;
75
+ }
76
+
77
+ export interface LicenseHeartbeatOptions {
78
+ licenseKey: string;
79
+ hardwareIdentifier: string;
80
+ customerId?: string;
81
+ productId?: string;
82
+ challenge?: string;
83
+ version?: string;
84
+ branch?: string;
85
+ }
86
+
87
+ export interface DownloadReleaseOptions {
88
+ licenseKey: string;
89
+ productId: string;
90
+ sessionKey: string;
91
+ hardwareIdentifier: string;
92
+ version: string;
93
+ customerId?: string;
94
+ branch?: string;
95
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": [
6
+ "ES2020"
7
+ ],
8
+ "declaration": true,
9
+ "outDir": "./dist",
10
+ "rootDir": "./src",
11
+ "strict": true,
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "moduleResolution": "node",
16
+ "resolveJsonModule": true
17
+ },
18
+ "include": [
19
+ "src/**/*"
20
+ ],
21
+ "exclude": [
22
+ "node_modules",
23
+ "dist"
24
+ ]
25
+ }