api-client.tsā¢7.1 kB
/**
* EuConquisto Composer HTTP API Client
*
* Direct API implementation to replace browser automation.
* Uses the discovered storage API endpoints for composition management.
*/
import { readFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
// Check if fetch is available globally (Node.js 18+)
const globalFetch = global.fetch || (typeof fetch !== 'undefined' ? fetch : null);
if (!globalFetch) {
throw new Error('This module requires Node.js 18+ with built-in fetch support, or a fetch polyfill');
}
export interface CompositionMetadata {
title: string;
description?: string;
thumb?: string | null;
tags?: string[];
}
export interface CompositionWidget {
id: string;
type: string;
content: string;
background_color?: string;
padding_top?: number;
padding_bottom?: number;
[key: string]: any; // Allow additional widget-specific properties
}
export interface CompositionData {
version: string;
metadata: CompositionMetadata;
interface: {
content_language: string;
index_option: string;
font_family: string;
show_summary: string;
finish_btn: string;
};
structure: CompositionWidget[];
}
export interface APIResponse {
success: boolean;
data?: any;
error?: string;
statusCode: number;
}
export class EuConquistoAPIClient {
private readonly baseURL = "https://api.digitalpages.com.br";
private readonly projectUID = "36c92686-c494-ec11-a22a-dc984041c95d";
private readonly jwtToken: string;
constructor() {
// Read the corrected JWT token from file (ES module compatible)
const currentDir = dirname(fileURLToPath(import.meta.url));
const tokenPath = resolve(currentDir, '../correct-jwt-new.txt');
this.jwtToken = readFileSync(tokenPath, 'utf8').trim();
}
/**
* Get authorization headers for API requests
*/
private getHeaders(): Record<string, string> {
return {
'Authorization': `Bearer ${this.jwtToken}`,
'User-Agent': 'EuConquisto-MCP-Client/1.0',
};
}
/**
* Create a new composition via the storage API
*/
async createComposition(compositionData: CompositionData, uid?: string): Promise<APIResponse> {
try {
const compositionUID = uid || this.generateUID();
const url = `${this.baseURL}/storage/v1.0/content?uid=${compositionUID}&manual_project_uid=${this.projectUID}`;
// Create the composition file content
const compositionJSON = JSON.stringify(compositionData, null, 2);
// Create FormData for multipart upload
const formData = new FormData();
const blob = new Blob([compositionJSON], { type: 'digitalpages/composer' });
formData.append('file', blob, 'composition.rdpcomposer');
const response = await fetch(url, {
method: 'POST',
headers: this.getHeaders(),
body: formData
});
const result = await response.json();
return {
success: response.ok,
data: result,
statusCode: response.status,
error: response.ok ? undefined : `API Error: ${response.status} ${response.statusText}`
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
statusCode: 0
};
}
}
/**
* Update an existing composition
*/
async updateComposition(uid: string, compositionData: CompositionData): Promise<APIResponse> {
try {
const url = `${this.baseURL}/storage/v1.0/content?uid=${uid}&manual_project_uid=${this.projectUID}`;
const compositionJSON = JSON.stringify(compositionData, null, 2);
const formData = new FormData();
const blob = new Blob([compositionJSON], { type: 'digitalpages/composer' });
formData.append('file', blob, 'composition.rdpcomposer');
const response = await fetch(url, {
method: 'PUT',
headers: this.getHeaders(),
body: formData
});
const result = await response.json();
return {
success: response.ok,
data: result,
statusCode: response.status,
error: response.ok ? undefined : `API Error: ${response.status} ${response.statusText}`
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
statusCode: 0
};
}
}
/**
* Test API connection
*/
async testConnection(): Promise<APIResponse> {
try {
// Test with a simple GET request to check authentication
const url = `${this.baseURL}/storage/v1.0/search?project_uid=${this.projectUID}&limit=1`;
const response = await fetch(url, {
method: 'GET',
headers: this.getHeaders()
});
let responseData;
try {
responseData = await response.json();
} catch {
responseData = await response.text();
}
return {
success: response.ok,
data: response.ok ? {
message: 'API connection successful',
endpoint: this.baseURL,
project: this.projectUID,
response: responseData
} : responseData,
statusCode: response.status,
error: response.ok ? undefined : `Connection failed: ${response.status} ${response.statusText}`
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Connection error',
statusCode: 0
};
}
}
/**
* Create a basic composition structure
*/
createBasicComposition(title: string, description?: string): CompositionData {
return {
version: "1.1",
metadata: {
title,
description: description || "",
thumb: null,
tags: []
},
interface: {
content_language: "pt_br",
index_option: "buttons",
font_family: "Lato",
show_summary: "disabled",
finish_btn: "disabled"
},
structure: []
};
}
/**
* Add a text widget to composition
*/
addTextWidget(content: string, backgroundColor: string = "#FFFFFF"): CompositionWidget {
return {
id: this.generateUID(),
type: "text-1",
content: `<p>${content}</p>`,
background_color: backgroundColor,
padding_top: 0,
padding_bottom: 0
};
}
/**
* Add a header widget to composition
*/
addHeaderWidget(title: string, subtitle?: string): CompositionWidget {
const content = subtitle
? `<h1>${title}</h1><h2>${subtitle}</h2>`
: `<h1>${title}</h1>`;
return {
id: this.generateUID(),
type: "head-1",
content,
background_color: "#FFFFFF",
padding_top: 20,
padding_bottom: 20
};
}
/**
* Generate a simple UID for widgets/compositions
*/
private generateUID(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
}