@letsparky/api-v2-client
Version:
TypeScript client for the LetsParky API V2
397 lines (396 loc) • 16.4 kB
JavaScript
"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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LetsParkyClient = exports.testUtils = exports.logger = exports.LogLevel = exports.Logger = exports.ErrorCodes = exports.createStandardError = exports.ConfigurationError = exports.RateLimitError = exports.TokenExpiredError = exports.ValidationError = exports.AuthenticationError = exports.NetworkError = exports.ApiError = exports.PaymentStatus = exports.PaymentType = exports.EntityStatus = exports.UserStatus = exports.UserRole = exports.UserGender = exports.ParkingAreaType = exports.ParkingStatus = exports.Environment = void 0;
const client_1 = require("./client");
const auth_1 = require("./auth");
const devices_1 = require("./devices");
const device_logs_1 = require("./device_logs");
const memberships_1 = require("./memberships");
const parkings_1 = require("./parkings");
const parking_areas_1 = require("./parking_areas");
const payments_1 = require("./payments");
const users_1 = require("./users");
const tenants_1 = require("./tenants");
const system_1 = require("./system");
const types_1 = require("./types");
const logger_1 = require("./logger");
Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.logger; } });
const errors_1 = require("./errors");
const testUtils = __importStar(require("./test-utils"));
exports.testUtils = testUtils;
// Export types explicitly
var types_2 = require("./types");
Object.defineProperty(exports, "Environment", { enumerable: true, get: function () { return types_2.Environment; } });
Object.defineProperty(exports, "ParkingStatus", { enumerable: true, get: function () { return types_2.ParkingStatus; } });
Object.defineProperty(exports, "ParkingAreaType", { enumerable: true, get: function () { return types_2.ParkingAreaType; } });
Object.defineProperty(exports, "UserGender", { enumerable: true, get: function () { return types_2.UserGender; } });
Object.defineProperty(exports, "UserRole", { enumerable: true, get: function () { return types_2.UserRole; } });
Object.defineProperty(exports, "UserStatus", { enumerable: true, get: function () { return types_2.UserStatus; } });
Object.defineProperty(exports, "EntityStatus", { enumerable: true, get: function () { return types_2.EntityStatus; } });
Object.defineProperty(exports, "PaymentType", { enumerable: true, get: function () { return types_2.PaymentType; } });
Object.defineProperty(exports, "PaymentStatus", { enumerable: true, get: function () { return types_2.PaymentStatus; } });
// Export errors explicitly
var errors_2 = require("./errors");
Object.defineProperty(exports, "ApiError", { enumerable: true, get: function () { return errors_2.ApiError; } });
Object.defineProperty(exports, "NetworkError", { enumerable: true, get: function () { return errors_2.NetworkError; } });
Object.defineProperty(exports, "AuthenticationError", { enumerable: true, get: function () { return errors_2.AuthenticationError; } });
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_2.ValidationError; } });
Object.defineProperty(exports, "TokenExpiredError", { enumerable: true, get: function () { return errors_2.TokenExpiredError; } });
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return errors_2.RateLimitError; } });
Object.defineProperty(exports, "ConfigurationError", { enumerable: true, get: function () { return errors_2.ConfigurationError; } });
Object.defineProperty(exports, "createStandardError", { enumerable: true, get: function () { return errors_2.createStandardError; } });
Object.defineProperty(exports, "ErrorCodes", { enumerable: true, get: function () { return errors_2.ErrorCodes; } });
var logger_2 = require("./logger");
Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return logger_2.Logger; } });
Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return logger_2.LogLevel; } });
/**
* Main client class for the LetsParky API v2.
*
* This is the primary entry point for interacting with the LetsParky API.
* It provides a unified interface that combines all API functionality including
* device management, parking operations, user management, tenant operations,
* and authentication.
*
* The client automatically handles:
* - Authentication and token management
* - Rate limiting and retries
* - Error handling and logging
* - Environment-specific configuration
*
* @example
* ```typescript
* // Basic usage with API key
* const client = new LetsParkyClient({
* apiKey: 'your-api-key',
* environment: Environment.PRODUCTION
* });
*
* // Usage with email/password
* const client = new LetsParkyClient({
* email: 'your-email',
* password: 'your-password',
* environment: Environment.STAGING
* });
*
* // Access specific functionality
* const devices = await client.listDevices();
* const parkings = await client.listParkings();
* const profile = await client.getProfile();
*
* // Or use the specialized clients directly
* const newDevice = await client.devices.create({
* name: 'Sensor 1',
* type: 'ultrasonic'
* });
* ```
*
* @since 1.0.0
*/
class LetsParkyClient {
/**
* Creates a new LetsParkyClient instance.
*
* @param config - Configuration options for the client
* @param config.apiKey - API key for authentication (alternative to email/password)
* @param config.baseUrl - Custom base URL for the API (overrides environment-based URL)
* @param config.timeout - Request timeout in milliseconds (default: 30000)
* @param config.email - Email for authentication (requires password)
* @param config.password - Password for authentication (requires email)
* @param config.environment - Target environment (default: PRODUCTION)
* @param config.logLevel - Logging level (default: INFO)
* @param config.silentLogs - Disable all logging (default: false)
* @param config.useHttps - Force HTTPS usage (default: false, auto-enabled for production)
* @param config.acceptSelfSigned - Accept self-signed certificates in development (default: false)
* @param config.rateLimitRetryCount - Number of retries when rate limited (default: 3)
* @param config.rateLimitRetryDelay - Base delay between retries in milliseconds (default: 1000)
*
* @example
* ```typescript
* // Production client with API key
* const client = new LetsParkyClient({
* apiKey: 'pk_live_...',
* environment: Environment.PRODUCTION,
* logLevel: LogLevel.WARN
* });
*
* // Development client with credentials
* const devClient = new LetsParkyClient({
* email: 'dev-user',
* password: 'dev-password',
* environment: Environment.DEVELOPMENT,
* useHttps: false,
* acceptSelfSigned: true,
* logLevel: LogLevel.DEBUG
* });
* ```
*
* @throws {ConfigurationError} When invalid configuration is provided
* @throws {AuthenticationError} When automatic authentication fails (if email/password provided)
*
* @since 1.0.0
*/
constructor(config = {}) {
this.client = new client_1.ApiClient(config);
this.auth = new auth_1.Auth(this.client);
this.devices = new devices_1.Devices(this.client);
this.deviceLogs = new device_logs_1.DeviceLogs(this.client);
this.memberships = new memberships_1.Memberships(this.client);
this.parkings = new parkings_1.Parkings(this.client);
this.parkingAreas = new parking_areas_1.ParkingAreas(this.client);
this.payments = new payments_1.Payments(this.client);
this.users = new users_1.Users(this.client);
this.tenants = new tenants_1.Tenants(this.client);
this.system = new system_1.System(this.client);
}
/**
* Sets the target environment for the client.
*
* This method changes the environment and automatically updates the base URL
* to match the selected environment. It also propagates the environment
* setting to validators and other components.
*
* @param environment - The target environment
*
* @example
* ```typescript
* const client = new LetsParkyClient();
*
* // Switch to development for testing
* client.setEnvironment(Environment.DEVELOPMENT);
*
* // Switch to production
* client.setEnvironment(Environment.PRODUCTION);
* ```
*
* @since 1.0.0
*/
setEnvironment(environment) {
this.client.setEnvironment(environment);
}
/**
* Sets the logging level for the client.
*
* This controls the verbosity of log output from the client and all
* its components. Higher levels include all lower levels.
*
* @param level - The logging level to set
*
* @example
* ```typescript
* const client = new LetsParkyClient();
*
* // Enable debug logging for development
* client.setLogLevel(LogLevel.DEBUG);
*
* // Only show errors in production
* client.setLogLevel(LogLevel.ERROR);
* ```
*
* @since 1.0.0
*/
setLogLevel(level) {
this.client.setLogLevel(level);
}
/**
* Authenticates the client using configured email and password.
*
* This is a convenience method that delegates to the underlying client's
* authenticate method. The client must have been configured with email
* and password for this to work.
*
* @returns Promise that resolves when authentication is successful
*
* @throws {AuthenticationError} When email/password are missing or authentication fails
* @throws {NetworkError} When the request fails due to network issues
*
* @example
* ```typescript
* const client = new LetsParkyClient({
* email: 'your-email',
* password: 'your-password'
* });
*
* try {
* await client.authenticate();
* console.log('Successfully authenticated');
* } catch (error) {
* console.error('Authentication failed:', error.message);
* }
* ```
*
* @since 1.0.0
*/
async authenticate() {
return this.client.authenticate();
}
/**
* Retrieves a list of all devices.
*
* This is a convenience method that delegates to the devices client.
* For more advanced device operations, use the `devices` property directly.
*
* @returns Promise resolving to an array of devices
*
* @throws {AuthenticationError} When authentication is required or fails
* @throws {ApiError} When the API returns an error response
* @throws {NetworkError} When the request fails due to network issues
*
* @example
* ```typescript
* const client = new LetsParkyClient({ apiKey: 'your-api-key' });
*
* const devices = await client.listDevices();
* console.log(`Found ${devices.length} devices`);
*
* devices.forEach(device => {
* console.log(`- ${device.name} (${device.type})`);
* });
* ```
*
* @since 1.0.0
*/
async listDevices() {
const devices = await this.devices.list();
return devices;
}
/**
* Get current rate limit information
*/
getRateLimitInfo() {
return this.client.getRateLimitInfo();
}
/**
* List all devices with pagination
* @param page Page number (starting from 1)
* @param limit Items per page
* @param filters Optional filters
*/
async listDevicesPaginated(page = 1, limit = 10, filters) {
const response = await this.devices.listPaginated({ page, limit }, filters);
return response.data;
}
/**
* List all parkings
* @param filters Optional filter parameters for parkings
*/
async listParkings(filters) {
const parkings = await this.parkings.list(filters);
return parkings;
}
/**
* Get user profile
* Convenience method that delegates to auth.getProfile()
*/
async getProfile() {
const response = await this.auth.getProfile();
return response.data;
}
/**
* List all tenants (SYSTEM only)
* @param filters Optional filter parameters for tenants
* Convenience method that delegates to tenants.list()
*/
async listTenants(filters) {
const response = await this.tenants.list(filters);
return response.data;
}
/**
* Check if the API endpoint is responding
* Useful for verifying connectivity before running tests
* @returns Promise that resolves to true if the API is online, false otherwise
*/
async isApiOnline() {
try {
// Try to access the base URL
await this.client.get('/');
return true;
}
catch (error) {
if (error instanceof errors_1.ApiError && error.status === 404) {
// 404 means the API is responding but the specific endpoint doesn't exist
return true;
}
return false;
}
}
/**
* Get device logs with optional filtering
* Convenience method that delegates to deviceLogs.list()
* @param filters Optional filter parameters for device logs
*/
async getDeviceLogs(filters) {
const response = await this.deviceLogs.list(filters);
return response.data;
}
/**
* Get analytics for a specific device
* Convenience method that delegates to deviceLogs.getAnalytics()
* @param deviceId The device ID to get analytics for
* @param params Optional time range parameters
*/
async getDeviceAnalytics(deviceId, params) {
const response = await this.deviceLogs.getAnalytics(deviceId, params);
return response.data;
}
/**
* Get the latest log for a specific device
* Convenience method that delegates to deviceLogs.getLatest()
* @param deviceId The device ID to get the latest log for
*/
async getLatestDeviceLog(deviceId) {
const response = await this.deviceLogs.getLatest(deviceId);
return response.data;
}
/**
* Download device logs as an Excel file.
* In browser contexts this will prompt the user with a file download dialog.
* In Node.js it resolves with a Buffer containing the file contents.
*
* @param filters Optional filter parameters (same as getDeviceLogs)
*/
async downloadDeviceLogs(filters) {
return this.deviceLogs.download(filters);
}
/**
* Initialize client with test/mock data
* Use this for testing when the actual API might not be available
* @param options Configuration for mock data
*/
setupTestEnvironment(options = {}) {
// Set up mock data as needed
if (options.authToken) {
this.client.setToken(options.authToken);
}
// Set environment to development
this.setEnvironment(types_1.Environment.DEVELOPMENT);
// Set log level to debug for testing
this.setLogLevel(types_1.LogLevel.DEBUG);
logger_1.logger.warn('Client initialized in TEST environment with mock data');
}
}
exports.LetsParkyClient = LetsParkyClient;
// Export LetsParkyClient as default
exports.default = LetsParkyClient;