@tupli/sdk
v0.1.0
Published
Official SDK for Tupli license verification
Maintainers
Readme
@tupli/sdk
Official TypeScript/JavaScript SDK for Tupli license verification.
Installation
npm install @tupli/sdk
# or
pnpm add @tupli/sdk
# or
yarn add @tupli/sdkQuick Start
import { Tupli } from "@tupli/sdk";
const tupli = new Tupli({
projectId: "proj_xxxxxxxxxxxxxxxx", // Your project ID from the dashboard
});
async function checkLicense(licenseKey: string) {
const result = await tupli.verify(licenseKey);
if (result.valid) {
console.log("License is valid!");
console.log("License ID:", result.license_id);
console.log("Metadata:", result.metadata);
console.log("Expires:", result.expires_at ?? "Never");
} else {
console.log("License invalid:", result.reason);
// result.reason is 'invalid_key' | 'revoked' | 'expired'
}
}Configuration
const tupli = new Tupli({
projectId: "proj_xxx", // Required: Your project ID
baseUrl: "https://...", // Optional: Custom API URL (default: https://api.tupli.dev)
timeout: 5000, // Optional: Request timeout in ms (default: 5000)
retries: 2, // Optional: Retry attempts for network errors (default: 0)
retryDelay: 1000, // Optional: Delay between retries in ms (default: 1000)
});Response Types
Valid License
{
valid: true,
license_id: "lic_xxxxxxxxxxxxxxxx",
metadata: {
plan: "pro",
features: ["export", "sync"]
},
expires_at: "2025-12-31T23:59:59Z" // or null for perpetual
}Invalid License
{
valid: false,
reason: "invalid_key" | "revoked" | "expired"
}Error Handling
The SDK throws errors for network and API issues (not for invalid licenses):
import {
Tupli,
TupliApiError,
TupliTimeoutError,
TupliNetworkError,
} from "@tupli/sdk";
try {
const result = await tupli.verify(licenseKey);
if (result.valid) {
// License is valid
enableFeatures(result.metadata);
} else {
// License is invalid (not an error)
showLicenseError(result.reason);
}
} catch (error) {
if (error instanceof TupliApiError) {
// API returned an error (4xx/5xx)
console.error("API error:", error.code, error.message, error.statusCode);
} else if (error instanceof TupliTimeoutError) {
// Request timed out
console.error("Request timed out");
} else if (error instanceof TupliNetworkError) {
// Network error (no internet, DNS failure, etc.)
console.error("Network error:", error.message);
}
}TypeScript
Full TypeScript support with exported types:
import type {
TupliConfig,
VerifyResponse,
VerifySuccessResponse,
VerifyFailureResponse,
LicenseMetadata,
} from "@tupli/sdk";
// Type guard for valid licenses
function isValidLicense(
response: VerifyResponse
): response is VerifySuccessResponse {
return response.valid === true;
}Examples
Electron App
import { Tupli } from "@tupli/sdk";
const tupli = new Tupli({ projectId: "proj_xxx" });
async function validateLicense() {
const licenseKey = store.get("licenseKey");
if (!licenseKey) {
showActivationDialog();
return;
}
const result = await tupli.verify(licenseKey);
if (result.valid) {
// Enable pro features based on metadata
if (result.metadata.plan === "pro") {
enableProFeatures();
}
} else {
// Handle based on reason
switch (result.reason) {
case "invalid_key":
showInvalidKeyError();
break;
case "revoked":
showRevokedError();
break;
case "expired":
showExpiredError();
break;
}
}
}CLI Tool
import { Tupli, TupliNetworkError } from "@tupli/sdk";
const tupli = new Tupli({
projectId: "proj_xxx",
timeout: 3000,
retries: 2,
});
async function checkLicense(key: string): Promise<boolean> {
try {
const result = await tupli.verify(key);
return result.valid;
} catch (error) {
if (error instanceof TupliNetworkError) {
// Offline - allow grace period or cached validation
return checkCachedLicense(key);
}
throw error;
}
}Requirements
- Node.js 18+ (uses native fetch)
- Or modern browser with fetch support
License
MIT
