UNPKG

@fairmint/canton-node-sdk

Version:
418 lines 19.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.EnvLoader = void 0; const dotenv_1 = require("dotenv"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const errors_1 = require("../errors"); // Load environment variables with fallback to parent directory const currentEnvPath = '.env'; const parentEnvPath = path.join('..', '.env'); // Try to load from current directory first let result = (0, dotenv_1.config)({ path: currentEnvPath }); // If no .env file found in current directory, try parent directory if (result.error && fs.existsSync(parentEnvPath)) { result = (0, dotenv_1.config)({ path: parentEnvPath }); } /** Singleton class for managing environment variables and configuration */ class EnvLoader { constructor(options = {}) { this.env = process.env; this.options = options; } static getInstance(options = {}) { if (!EnvLoader.instance) { EnvLoader.instance = new EnvLoader(options); } else if (options.currentNetwork || options.currentProvider) { // Update existing instance with new options EnvLoader.instance.options = { ...EnvLoader.instance.options, ...options }; } return EnvLoader.instance; } static resetInstance() { EnvLoader.instance = undefined; } /** * Get configuration for a specific API type from environment variables * * @param apiType The API type to get configuration for * @param options Optional network and provider to use instead of reading from env * @returns ClientConfig with only the specified API configured */ static getConfig(apiType, options) { const envLoader = EnvLoader.getInstance(); // Determine which values to use - prioritize options over environment const network = options?.network ?? envLoader.getCurrentNetwork(); // Get provider, with special handling for localnet let provider = options?.provider; if (!provider) { // For localnet, default to 'app-provider' if not specified if (network === 'localnet') { provider = 'app-provider'; } else { // For other networks, require provider from environment provider = envLoader.getCurrentProvider(); } } if (!provider) { throw new errors_1.ConfigurationError(`Provider is required for ${apiType}. Either specify it in options or set CANTON_CURRENT_PROVIDER in environment.`); } const authUrl = envLoader.getAuthUrl(network, provider); // Get API-specific configuration using the determined network and provider const apiConfig = envLoader.loadApiConfig(apiType, network, provider || undefined); if (!apiConfig) { const providerStr = provider ? provider.toUpperCase() : 'PROVIDER'; throw new errors_1.ConfigurationError(`Missing required environment variables for ${apiType}. ` + `Required: CANTON_${network.toUpperCase()}_${providerStr}_${apiType.toUpperCase()}_URI, ` + `CANTON_${network.toUpperCase()}_${providerStr}_${apiType.toUpperCase()}_CLIENT_ID, ` + `and either CLIENT_SECRET (for client_credentials) or USERNAME/PASSWORD (for password grant)`); } const clientConfig = { network, apis: { [apiType]: apiConfig, }, }; clientConfig.provider = provider; clientConfig.authUrl = authUrl; return clientConfig; } /** * Get a summary of the environment variables being used for a specific configuration This is useful for debugging * configuration issues */ static getConfigSummary(apiType, options) { const envLoader = EnvLoader.getInstance(); const network = options?.network ?? envLoader.getCurrentNetwork(); const provider = options?.provider ?? envLoader.getCurrentProvider(); const envVars = {}; const missingVars = []; if (provider) { const upperNetwork = network.toUpperCase(); const upperProvider = provider.toUpperCase(); const baseKey = `CANTON_${upperNetwork}_${upperProvider}`; // API-specific variables envVars[`${baseKey}_${apiType.toUpperCase()}_URI`] = envLoader.env[`${baseKey}_${apiType.toUpperCase()}_URI`]; envVars[`${baseKey}_${apiType.toUpperCase()}_CLIENT_ID`] = envLoader.env[`${baseKey}_${apiType.toUpperCase()}_CLIENT_ID`]; envVars[`${baseKey}_${apiType.toUpperCase()}_CLIENT_SECRET`] = envLoader.env[`${baseKey}_${apiType.toUpperCase()}_CLIENT_SECRET`]; envVars[`${baseKey}_${apiType.toUpperCase()}_USERNAME`] = envLoader.env[`${baseKey}_${apiType.toUpperCase()}_USERNAME`]; envVars[`${baseKey}_${apiType.toUpperCase()}_PASSWORD`] = envLoader.env[`${baseKey}_${apiType.toUpperCase()}_PASSWORD`]; // Common variables envVars[`${baseKey}_AUTH_URL`] = envLoader.env[`${baseKey}_AUTH_URL`]; envVars[`${baseKey}_PARTY_ID`] = envLoader.env[`${baseKey}_PARTY_ID`]; envVars[`${baseKey}_USER_ID`] = envLoader.env[`${baseKey}_USER_ID`]; if (!envVars[`${baseKey}_${apiType.toUpperCase()}_URI`]) { missingVars.push(`${baseKey}_${apiType.toUpperCase()}_URI`); } if (!envVars[`${baseKey}_${apiType.toUpperCase()}_CLIENT_ID`]) { missingVars.push(`${baseKey}_${apiType.toUpperCase()}_CLIENT_ID`); } if (!envVars[`${baseKey}_AUTH_URL`]) { missingVars.push(`${baseKey}_AUTH_URL`); } } // Add template and contract IDs to the summary const walletTemplateKey = `CANTON_WALLET_TEMPLATE_ID_${network.toUpperCase()}`; const preapprovalTemplateKey = `CANTON_PREAPPROVAL_TEMPLATE_ID_${network.toUpperCase()}`; const amuletRulesContractKey = `CANTON_AMULET_RULES_CONTRACT_ID_${network.toUpperCase()}`; const validatorWalletAppInstallContractKey = `CANTON_VALIDATOR_WALLET_APP_INSTALL_CONTRACT_ID_${network.toUpperCase()}`; envVars[walletTemplateKey] = envLoader.env[walletTemplateKey]; envVars[preapprovalTemplateKey] = envLoader.env[preapprovalTemplateKey]; envVars[amuletRulesContractKey] = envLoader.env[amuletRulesContractKey]; envVars[validatorWalletAppInstallContractKey] = envLoader.env[validatorWalletAppInstallContractKey]; // Check for missing template and contract variables if (!envVars[walletTemplateKey]) { missingVars.push(walletTemplateKey); } if (!envVars[preapprovalTemplateKey]) { missingVars.push(preapprovalTemplateKey); } if (!envVars[amuletRulesContractKey]) { missingVars.push(amuletRulesContractKey); } if (!envVars[validatorWalletAppInstallContractKey]) { missingVars.push(validatorWalletAppInstallContractKey); } return { network, provider, envVars, missingVars, }; } getNodeEnv() { const value = this.env['NODE_ENV'] ?? 'development'; if (!['development', 'production', 'test'].includes(value)) { throw new errors_1.ConfigurationError(`Invalid NODE_ENV: ${value}. Must be 'development', 'production', or 'test'`); } return value; } getCurrentNetwork() { if (this.options.currentNetwork) { return this.options.currentNetwork; } const value = this.env['CANTON_CURRENT_NETWORK']?.toLowerCase(); if (!value || !['devnet', 'testnet', 'mainnet', 'localnet'].includes(value)) { throw new errors_1.ConfigurationError('Missing or invalid CANTON_CURRENT_NETWORK. Must be "devnet", "testnet", "mainnet", or "localnet"'); } return value; } getCurrentProvider() { if (this.options.currentProvider) { return this.options.currentProvider; } const value = this.env['CANTON_CURRENT_PROVIDER']?.toLowerCase(); if (!value) { throw new errors_1.ConfigurationError('Missing or invalid CANTON_CURRENT_PROVIDER'); } return value; } getApiUri(apiType, network, provider) { const targetNetwork = network ?? this.getCurrentNetwork(); // Special case for APIs that don't require provider-specific configuration if (apiType === 'LIGHTHOUSE_API') { const envKey = `CANTON_${targetNetwork.toUpperCase()}_${apiType.toUpperCase()}_URI`; const uri = this.env[envKey]; return uri; } const targetProvider = provider ?? this.getCurrentProvider(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_${targetProvider.toUpperCase()}_${apiType.toUpperCase()}_URI`; const uri = this.env[envKey]; return uri; } getApiClientId(apiType, network, provider) { const targetNetwork = network ?? this.getCurrentNetwork(); const targetProvider = provider ?? this.getCurrentProvider(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_${targetProvider.toUpperCase()}_${apiType.toUpperCase()}_CLIENT_ID`; return this.env[envKey]; } getApiClientSecret(apiType, network, provider) { const targetNetwork = network ?? this.getCurrentNetwork(); const targetProvider = provider ?? this.getCurrentProvider(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_${targetProvider.toUpperCase()}_${apiType.toUpperCase()}_CLIENT_SECRET`; return this.env[envKey]; } getApiUsername(apiType, network, provider) { const targetNetwork = network ?? this.getCurrentNetwork(); const targetProvider = provider ?? this.getCurrentProvider(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_${targetProvider.toUpperCase()}_${apiType.toUpperCase()}_USERNAME`; return this.env[envKey]; } getApiPassword(apiType, network, provider) { const targetNetwork = network ?? this.getCurrentNetwork(); const targetProvider = provider ?? this.getCurrentProvider(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_${targetProvider.toUpperCase()}_${apiType.toUpperCase()}_PASSWORD`; return this.env[envKey]; } getAuthUrl(network, provider) { const targetNetwork = network ?? this.getCurrentNetwork(); const targetProvider = provider ?? this.getCurrentProvider(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_${targetProvider.toUpperCase()}_AUTH_URL`; const authUrl = this.env[envKey]; // Provide localnet defaults for cn-quickstart if (!authUrl && targetNetwork === 'localnet') { if (targetProvider === 'app-provider') { return 'http://localhost:8082/realms/AppProvider/protocol/openid-connect/token'; } if (targetProvider === 'app-user') { return 'http://localhost:8082/realms/AppUser/protocol/openid-connect/token'; } } if (!authUrl) { throw new errors_1.ConfigurationError(`Missing required environment variable: ${envKey}`); } return authUrl; } getPartyId(network, provider) { const targetNetwork = network ?? this.getCurrentNetwork(); const targetProvider = provider ?? this.getCurrentProvider(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_${targetProvider.toUpperCase()}_PARTY_ID`; const partyId = this.env[envKey]; if (!partyId) { throw new errors_1.ConfigurationError(`Missing required environment variable: ${envKey}`); } return partyId; } getUserId(network, provider) { const targetNetwork = network ?? this.getCurrentNetwork(); const targetProvider = provider ?? this.getCurrentProvider(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_${targetProvider.toUpperCase()}_USER_ID`; return this.env[envKey]; } getDatabaseUrl(network) { const targetNetwork = network ?? this.getCurrentNetwork(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_DATABASE_URL`; const databaseUrl = this.env[envKey]; if (!databaseUrl) { throw new errors_1.ConfigurationError(`Missing required environment variable: ${envKey}`); } return databaseUrl; } getManagedParties(network, provider) { const targetNetwork = network ?? this.getCurrentNetwork(); const targetProvider = provider ?? this.getCurrentProvider(); const envKey = `CANTON_${targetNetwork.toUpperCase()}_${targetProvider.toUpperCase()}_MANAGED_PARTIES`; const managedParties = this.env[envKey]; if (!managedParties) { return []; } return managedParties .split(',') .map((party) => party.trim()) .filter((party) => party.length > 0); } getAmuletRulesContractId(network) { const targetNetwork = network ?? this.getCurrentNetwork(); const envKey = `CANTON_AMULET_RULES_CONTRACT_ID_${targetNetwork.toUpperCase()}`; const contractId = this.env[envKey]; if (!contractId) { throw new errors_1.ConfigurationError(`Missing required environment variable: ${envKey}`); } return contractId; } getValidatorWalletAppInstallContractId(network) { const targetNetwork = network ?? this.getCurrentNetwork(); const envKey = `CANTON_VALIDATOR_WALLET_APP_INSTALL_CONTRACT_ID_${targetNetwork.toUpperCase()}`; const contractId = this.env[envKey]; if (!contractId) { throw new errors_1.ConfigurationError(`Missing required environment variable: ${envKey}`); } return contractId; } /** * Get localnet defaults for cn-quickstart These are the standard OAuth2 credentials and URLs for cn-quickstart with * OAuth2 enabled */ getLocalnetDefaults(apiType, provider) { if (provider !== 'app-provider' && provider !== 'app-user') { return undefined; } const portPrefix = provider === 'app-provider' ? '3' : '2'; // Default OAuth2 credentials for cn-quickstart const auth = { grantType: 'client_credentials', clientId: `${provider}-validator`, clientSecret: provider === 'app-provider' ? 'AL8648b9SfdTFImq7FV56Vd0KHifHBuC' : 'k1YVWeC1vjQcqzlqzY98WVxJc6e4IIdZ', }; // Map API types to their port suffixes const apiUrlMap = { VALIDATOR_API: `http://localhost:${portPrefix}903`, LEDGER_JSON_API: `http://localhost:${portPrefix}975`, SCAN_API: `http://localhost:4000/api/scan`, }; const apiUrl = apiUrlMap[apiType]; if (!apiUrl) { return undefined; } return { apiUrl, auth, }; } loadApiConfig(apiType, network, provider) { if (!provider) { return undefined; // Provider must be specified to load this API configuration } // For localnet, try defaults first if environment variables are not set if (network === 'localnet') { const apiUrl = this.getApiUri(apiType, network, provider); const clientId = this.getApiClientId(apiType, network, provider); // If no environment variables are set, use localnet defaults if (!apiUrl && !clientId) { return this.getLocalnetDefaults(apiType, provider); } } const apiUrl = this.getApiUri(apiType, network, provider); const clientId = this.getApiClientId(apiType, network, provider); const clientSecret = this.getApiClientSecret(apiType, network, provider); const username = this.getApiUsername(apiType, network, provider); const password = this.getApiPassword(apiType, network, provider); const partyId = this.getPartyId(network, provider); const userId = this.getUserId(network, provider); if (!apiUrl || !clientId) { return undefined; } // Determine grant type based on available credentials let grantType; let auth; if (clientSecret) { // Use client_credentials if client secret is available grantType = 'client_credentials'; auth = { grantType, clientId, clientSecret, }; } else if (username && password) { // Use password grant if username and password are available grantType = 'password'; auth = { grantType, clientId, username, password, }; } else { // Fallback to client_credentials without secret (some providers may not require it) grantType = 'client_credentials'; auth = { grantType, clientId, }; } const apiConfig = { apiUrl, auth, }; if (partyId) { apiConfig.partyId = String(partyId); } if (userId) { apiConfig.userId = String(userId); } return apiConfig; } } exports.EnvLoader = EnvLoader; //# sourceMappingURL=EnvLoader.js.map