@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
104 lines • 3.5 kB
JavaScript
import { ApiKeyStamper } from '@turnkey/api-key-stamper';
import { TurnkeyServerClient } from '@turnkey/sdk-server';
import { deepCopy, rootLogger } from '@hyperlane-xyz/utils';
const logger = rootLogger.child({ module: 'sdk:turnkey-client' });
/**
* Extract safe error message from error object
* Avoids logging sensitive data like API keys, stack traces, etc.
* Handles TurnkeyActivityError, TurnkeyRequestError, and standard Error types
*/
function getSafeErrorMessage(error) {
if (error instanceof Error) {
return error.message;
}
return 'Unknown error';
}
/**
* Log Turnkey operation error safely without exposing sensitive data
* Accepts unknown errors from catch blocks and safely extracts error messages
*/
export function logTurnkeyError(operation, error) {
const errorMessage = getSafeErrorMessage(error);
logger.error(`${operation}:`, errorMessage);
}
/**
* Validate that a Turnkey activity completed successfully
* The Turnkey SDK polls internally until the activity completes or max retries are reached.
* If we receive a non-completed status, it indicates an SDK bug or request error.
*/
export function validateTurnkeyActivityCompleted(activity, operationType) {
if (activity.status !== 'ACTIVITY_STATUS_COMPLETED') {
throw new Error(`${operationType} activity did not complete. Status: ${activity.status}`);
}
}
/**
* Default Turnkey API base URL
*/
export const DEFAULT_TURNKEY_API_BASE_URL = 'https://api.turnkey.com';
/**
* Shared Turnkey client manager
* Handles initialization, health checks, and provides access to the Turnkey client
*
* This class is used by all VM-specific signers via composition rather than inheritance,
* allowing each signer to extend/implement their VM-specific base classes while
* still sharing common Turnkey functionality.
*
* @example
* ```typescript
* const manager = new TurnkeyClientManager(config);
* await manager.healthCheck();
* const client = manager.getClient();
* ```
*/
export class TurnkeyClientManager {
client;
config;
constructor(config) {
this.config = config;
const stamper = new ApiKeyStamper({
apiPublicKey: config.apiPublicKey,
apiPrivateKey: config.apiPrivateKey,
});
this.client = new TurnkeyServerClient({
organizationId: config.organizationId,
stamper,
apiBaseUrl: config.apiBaseUrl || DEFAULT_TURNKEY_API_BASE_URL,
});
}
/**
* Get a copy of the configuration (for creating new signer instances)
*/
getConfig() {
return deepCopy(this.config);
}
/**
* Get the Turnkey client (for signing operations)
*/
getClient() {
return this.client;
}
/**
* Get organization ID
*/
getOrganizationId() {
return this.config.organizationId;
}
/**
* Check if Turnkey is properly configured and accessible
*/
async healthCheck() {
try {
logger.debug('Running Turnkey health check...');
const whoami = await this.client.getWhoami({
organizationId: this.config.organizationId,
});
logger.debug(`Turnkey health check passed. Organization ID: ${whoami.organizationId}`);
return true;
}
catch (error) {
logTurnkeyError('Turnkey health check failed', error);
return false;
}
}
}
//# sourceMappingURL=turnkeyClient.js.map