Node.js SDK AI Prompt

Copy/paste this prompt into your AI assistant (e.g., GitHub Copilot Chat, Cursor, ChatGPT) to integrate the ExisOne Node.js SDK into your application.

Prompt

You're assisting me in integrating the ExisOne Node.js SDK for software licensing.

GOAL
- Generate a stable hardware ID on first run
- Activate a license with user input (activation key + email) and report app version
- Validate the license on every app start (online or offline) with version checking
- Check for software updates by comparing client version to server version
- Deactivate the license from the same hardware when requested
- Support offline customers with RSA-signed offline activation codes
- Submit support tickets from within the app

CONTEXT
- SDK package: exisone-client (version 0.7.0)
- Node.js: 18+ (uses native fetch)
- Full TypeScript support included
- I have an API base URL and an access token (format: exo_at_<public>_<secret>)
- Validate requires 'verify' permission on the access token
- For offline validation, I have an RSA public key (PEM format) from the Crypto Keys page
- Server may enforce minimum version requirements - client must handle version_outdated status
- Zero external dependencies

REQUIREMENTS
1) Install the package:
   npm install exisone-client
   # or: yarn add exisone-client / pnpm add exisone-client

2) Initialize the client:
   import { ExisOneClient } from 'exisone-client';

   const client = new ExisOneClient({
       baseUrl: 'https://YOUR-API-HOST',
       accessToken: 'exo_at_PUBLIC_SECRET',
       offlinePublicKey: `-----BEGIN PUBLIC KEY-----
   MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...
   -----END PUBLIC KEY-----`  // Optional: for offline license validation
   });

   // Log SDK version
   console.log(`ExisOne SDK: ${client.getVersion()}`);

3) Hardware ID:
   - On first run, compute client.generateHardwareId(), persist locally (e.g., config file, electron-store)
   - Reuse the persisted value thereafter
   - Display to user so they can request offline licenses if needed

4) Activation flow with version:
   - Ask for Activation Key (or Offline Code) and Email
   - For online keys with version check:
     const result = await client.activate({
         activationKey: key,
         email: email,
         hardwareId: hardwareId,
         productName: 'MyProduct',
         version: '1.0.0'
     });

     if (!result.success) {
         if (result.errorCode === 'version_outdated') {
             // User must upgrade before activating
             showError(`Please upgrade to version ${result.minimumRequiredVersion}`);
         } else {
             showError(result.errorMessage);
         }
     } else {
         // Activation successful - optionally notify about updates
         if (result.serverVersion !== '1.0.0') {
             showInfo(`Update available: v${result.serverVersion}`);
         }
     }
   - For offline codes: use validateOffline() or validateSmart() - no activation needed

5) Validation with version check:
   - Rich validation with version:
     const result = await client.validate({
         activationKey: key,
         hardwareId: hwid,
         productName: 'MyProduct',
         version: '1.0.0'
     });

     if (result.status === 'version_outdated') {
         // Force upgrade - license valid but version too old
         showError(`Please upgrade to version ${result.minimumRequiredVersion} to continue`);
         return;
     }
     if (result.isValid) {
         console.log(`Licensed until: ${result.expirationDate}`);
         console.log(`Features: ${result.features.join(', ')}`);
         // Optionally check for updates
         if (result.serverVersion && result.serverVersion !== '1.0.0') {
             showInfo(`Update available: v${result.serverVersion}`);
         }
     }

   - Smart validation (handles online/offline):
     const result = await client.validateSmart({
         activationKeyOrOfflineCode: keyOrCode,
         hardwareId: hwid,
         productName: 'MyProduct'
     });
     // result.serverVersion and result.minimumRequiredVersion available

6) Offline-only validation (no network):
   - const result = client.validateOffline(offlineCode, hardwareId);
   - Check result.isValid, result.isExpired, result.hardwareMismatch
   - Use when you know the user has an offline code and want zero network calls

7) Deactivation flow:
   - For smart deactivation (tries server, succeeds locally if offline):
     const result = await client.deactivateSmart({
         activationKeyOrOfflineCode: keyOrCode,
         hardwareId: hwid,
         productName: 'MyProduct'
     });
     console.log(`Success: ${result.success}, Server notified: ${result.serverNotified}`);
   - Legacy online-only:
     await client.deactivate({
         activationKey: key,
         hardwareId: hwid,
         productName: 'MyProduct'
     });

8) Support tickets:
   - Provide a form (product, email, subject, message)
   - Call:
     await client.sendSupportTicket({
         productName: 'MyProduct',
         email: userEmail,
         subject: 'Subject',
         message: 'Message body'
     });

9) Offline license workflow for customers without internet:
   - Customer sees their Hardware ID in your app (from generateHardwareId())
   - Customer contacts you (email/phone) with their Hardware ID
   - You generate an Offline Activation Code in the License Keys dashboard
   - Customer enters the long code into your app
   - Your app validates using validateOffline() or validateSmart()

10) Tenancy:
    - Ensure the access token belongs to the same tenant that owns the activation keys

11) Version enforcement handling:
    - Always pass your app's version during activation and validation
    - Handle 'version_outdated' status by prompting user to upgrade
    - Use serverVersion to notify users when updates are available
    - minimumRequiredVersion tells you the oldest acceptable version

12) Error handling:
    try {
        const result = await client.validate({ activationKey, hardwareId });
    } catch (err) {
        if (err instanceof Error) {
            console.log(`Error: ${err.message}`);
        }
    }

OFFLINE CODE SECURITY
- Offline codes are RSA-SHA256 signed (Base32 encoded with dashes)
- They embed: product ID, hardware ID, expiration date, email, features
- Cannot be forged, transferred, or modified
- Expiration is checked against local machine time

TYPESCRIPT TYPES (0.7.0)
interface ActivationResult {
    success: boolean;
    errorCode?: string;
    errorMessage?: string;
    serverVersion?: string;
    minimumRequiredVersion?: string;
    licenseData?: string;
}

interface ValidationResult {
    isValid: boolean;
    status: string;
    expirationDate?: Date;
    features: string[];
    serverVersion?: string;
    minimumRequiredVersion?: string;
}

interface OfflineValidationResult {
    isValid: boolean;
    errorMessage?: string;
    productName?: string;
    expirationDate?: Date;
    features: string[];
    isExpired: boolean;
    hardwareMismatch: boolean;
}

interface SmartValidationResult {
    isValid: boolean;
    status: string;
    expirationDate?: Date;
    features: string[];
    wasOffline: boolean;
    errorMessage?: string;
    productName?: string;
    serverVersion?: string;
    minimumRequiredVersion?: string;
}

interface DeactivationResult {
    success: boolean;
    serverNotified: boolean;
    errorMessage?: string;
}

ELECTRON APPS
// main.js (Electron main process)
const { ExisOneClient } = require('exisone-client');

const client = new ExisOneClient({
    baseUrl: 'https://www.exisone.com',
    accessToken: process.env.EXISONE_TOKEN
});

// Generate hardware ID once at startup
const hardwareId = client.generateHardwareId();

// Expose to renderer via IPC
ipcMain.handle('validate-license', async (event, activationKey) => {
    return client.validate({ activationKey, hardwareId });
});

DELIVERABLES
- Add initialization and configuration code
- Implement activation UI supporting both online keys and offline codes
- Pass app version during activation and validation
- Handle version_outdated status with upgrade prompts
- Optionally notify users when serverVersion differs from current version
- Use validateSmart() for seamless online/offline handling
- Provide code snippets for persistence of hardware ID and license key/code
- Display hardware ID to users for offline license requests
- Ensure proper async/await usage and error handling

Please produce idiomatic TypeScript/JavaScript for my stack (Node.js/Electron/Express/etc. as applicable), with concise functions and no extraneous commentary.

Notes