UNPKG

beeswax-node-client

Version:

TypeScript/JavaScript client library for the Beeswax DSP API

265 lines 10.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BeeswaxClient = void 0; const axios_1 = __importDefault(require("axios")); const axios_retry_1 = __importDefault(require("axios-retry")); const form_data_1 = __importDefault(require("form-data")); const resources_1 = require("./resources"); const CampaignMacros_1 = require("./macros/CampaignMacros"); class BeeswaxClient { constructor(options) { if (!options.creds || !options.creds.email || !options.creds.password) { throw new Error('Must provide creds object with email + password'); } if (!options.apiRoot) { throw new Error('Must provide apiRoot in options (e.g., https://example.api.beeswax.com)'); } this.apiRoot = options.apiRoot; this.creds = options.creds; // Setup axios instance with defaults this.axiosInstance = axios_1.default.create({ baseURL: this.apiRoot, timeout: options.timeout || 30000, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, withCredentials: true }); // Setup retry logic if (options.retryOptions) { (0, axios_retry_1.default)(this.axiosInstance, { retries: options.retryOptions.retries || 3, retryDelay: options.retryOptions.retryDelay || axios_retry_1.default.exponentialDelay, retryCondition: options.retryOptions.retryCondition || axios_retry_1.default.isNetworkOrIdempotentRequestError }); } // Setup request/response interceptors this.setupInterceptors(); // Initialize resources this.advertisers = new resources_1.AdvertiserResource(this); this.campaigns = new resources_1.CampaignResource(this); this.lineItems = new resources_1.LineItemResource(this); this.creatives = new resources_1.CreativeResource(this); this.creativeLineItems = new resources_1.CreativeLineItemResource(this); this.targetingTemplates = new resources_1.TargetingTemplateResource(this); this.creativeAssets = new resources_1.CreativeAssetResource(this); this.segments = new resources_1.SegmentResource(this); this.reports = new resources_1.ReportResource(this); // Initialize macros this.macros = new CampaignMacros_1.CampaignMacros(this); } setupInterceptors() { // Request interceptor to add cookies this.axiosInstance.interceptors.request.use((config) => { if (this.sessionCookies) { config.headers['Cookie'] = this.sessionCookies; } return config; }, (error) => Promise.reject(error)); // Response interceptor to save cookies and handle errors this.axiosInstance.interceptors.response.use((response) => { // Save cookies from set-cookie header const setCookies = response.headers['set-cookie']; if (setCookies) { this.sessionCookies = setCookies.join('; '); } return response; }, async (error) => { // Handle 401 unauthorized if (error.response?.status === 401 && !error.config._retry) { error.config._retry = true; await this.authenticate(); return this.axiosInstance(error.config); } return Promise.reject(error); }); } async authenticate() { // Prevent multiple simultaneous auth requests if (this.authPromise) { return this.authPromise; } this.authPromise = this.performAuthentication(); try { await this.authPromise; } finally { this.authPromise = undefined; } } async performAuthentication() { try { const response = await this.axiosInstance.post('/rest/authenticate', { email: this.creds.email, password: this.creds.password, keep_logged_in: true }); if (response.data.success === false) { throw new Error(`Authentication failed: ${JSON.stringify(response.data)}`); } } catch (error) { if (error.response) { throw new Error(`Authentication failed: ${error.response.status} - ${JSON.stringify(error.response.data)}`); } throw error; } } async request(method, endpoint, options) { const config = { method, url: endpoint, headers: options?.headers }; // For GET requests, use params instead of data if (method.toUpperCase() === 'GET') { config.params = options?.body || options?.params; } else { config.data = options?.body; config.params = options?.params; } try { const response = await this.axiosInstance.request(config); if (response.data.success === false) { throw new Error(JSON.stringify(response.data)); } return response.data; } catch (error) { if (error.response?.data) { throw error.response.data; } throw error; } } async uploadCreativeAsset(params) { if (!params.sourceUrl) { throw new Error('uploadCreativeAsset params requires a sourceUrl property.'); } // Get file size if not provided const assetDef = { advertiser_id: params.advertiser_id, creative_asset_name: params.creative_asset_name, notes: params.notes, active: params.active !== undefined ? params.active : true }; // Extract filename from URL if not provided if (!assetDef.creative_asset_name) { const urlParts = params.sourceUrl.split('/'); assetDef.creative_asset_name = urlParts[urlParts.length - 1]; } // Get file size if not provided if (!params.size_in_bytes) { try { const headResponse = await axios_1.default.head(params.sourceUrl); assetDef.size_in_bytes = parseInt(headResponse.headers['content-length'] || '0', 10); } catch (_error) { console.warn('Unable to detect content-length of sourceUrl:', params.sourceUrl); } } else { assetDef.size_in_bytes = params.size_in_bytes; } // Create the asset const createResponse = await this.request('POST', '/rest/creative_asset', { body: assetDef }); if (!createResponse.payload?.id) { throw new Error('Failed to create creative asset'); } const assetId = createResponse.payload.id; // Upload the file const form = new form_data_1.default(); const fileStream = await axios_1.default.get(params.sourceUrl, { responseType: 'stream' }); form.append('creative_content', fileStream.data); await this.request('POST', `/rest/creative_asset/upload/${assetId}`, { body: form, headers: form.getHeaders() }); // Get the updated asset const assetResponse = await this.creativeAssets.find(assetId); if (!assetResponse.payload) { throw new Error('Failed to retrieve uploaded creative asset'); } return assetResponse.payload; } // Utility method to get current user info async getCurrentUser() { try { // Create a minimal request without extra headers that cause issues const response = await axios_1.default.get(`${this.apiRoot}/rest/user/current`, { headers: { 'Cookie': this.sessionCookies || '' }, withCredentials: true }); return response.data; } catch (error) { if (error.response?.data) { return error.response.data; } throw error; } } // Utility method to get account info async getAccountInfo() { return this.request('GET', '/rest/account'); } // Helper method to create a line item with sensible defaults async createLineItem(params) { // Get campaign details to inherit settings const campaignResponse = await this.campaigns.find(params.campaign_id); if (!campaignResponse.success || !campaignResponse.payload) { throw new Error('Campaign not found'); } const campaign = campaignResponse.payload; // Build line item with all required fields const lineItemData = { advertiser_id: campaign.advertiser_id, campaign_id: params.campaign_id, line_item_name: params.line_item_name, line_item_budget: params.line_item_budget, line_item_type_id: 0, budget_type: 2, currency: campaign.currency || 'USD', // Bidding configuration bidding: { bidding_strategy: 'CPM_PACED', values: { cpm_bid: params.cpm_bid || 3 }, pacing: 'lifetime', bid_shading: true, pacing_behavior: 'even', catchup_behavior: 'even', bid_shading_win_rate_control: 'NORMAL', custom: false, multiplier: 1 }, // Dates - inherit from campaign if not provided start_date: params.start_date || campaign.start_date, end_date: params.end_date || campaign.end_date, // Other settings active: params.active !== undefined ? params.active : false, guaranteed: false, creative_weighting_method: 'RANDOM', frequency_cap: [], frequency_cap_type: 0, frequency_cap_vendor: null }; // Add targeting expression if provided if (params.targeting_expression_id) { lineItemData.targeting_expression_id = params.targeting_expression_id; } return this.lineItems.create(lineItemData); } } exports.BeeswaxClient = BeeswaxClient; //# sourceMappingURL=BeeswaxClient.js.map