@ai-growth/n8n-nodes-wordpress
Version:
n8n node for WordPress integration with AI GROWTH - SEO WP plugin
700 lines (698 loc) • 34.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContentService = void 0;
const ErrorUtils_1 = require("../utils/ErrorUtils");
const SeoService_1 = require("./SeoService");
const FaqService_1 = require("./FaqService");
const CtaService_1 = require("./CtaService");
/**
* Serviço para gerenciamento de conteúdo do WordPress
*/
class ContentService {
/**
* Construtor do serviço
* @param client Cliente WordPress
*/
constructor(client) {
this.parameterSupportCache = new Map();
this.client = client;
this.seoService = new SeoService_1.SeoService(client);
this.faqService = new FaqService_1.FaqService(client, this.seoService);
this.ctaService = new CtaService_1.CtaService(client, this.seoService);
}
/**
* Valida se um endpoint está disponível antes de fazer a requisição
* @param endpoint Endpoint a ser validado
* @param method Método HTTP (padrão: GET)
* @returns True se o endpoint estiver disponível
*/
async validateEndpointAvailability(endpoint, method = 'GET') {
try {
const isValid = await this.client.validateEndpoint(endpoint, method);
if (!isValid) {
// Tentar descobrir rotas se a validação falhar
const discovery = await this.client.discoverRoutes(false);
if (!discovery.success) {
// Se a descoberta de rotas falhar, assumir que o endpoint pode estar disponível
// para manter compatibilidade com versões antigas do WordPress
return true;
}
return false;
}
return true;
}
catch (error) {
// Em caso de erro na validação, assumir que o endpoint está disponível
// para evitar bloquear operações em casos onde a descoberta de rotas não funciona
return true;
}
}
/**
* Testa se um endpoint suporta parâmetros específicos
* @param endpoint Endpoint a ser testado
* @param parameters Parâmetros a serem testados
* @returns True se os parâmetros são suportados
*/
async testParameterSupport(endpoint, parameters) {
const cacheKey = `${endpoint}_${parameters.join(',')}`;
// Verificar cache primeiro
if (this.parameterSupportCache.has(cacheKey)) {
return this.parameterSupportCache.get(cacheKey);
}
try {
// Fazer uma requisição de teste com parâmetros vazios para verificar se são aceitos
const testParams = {};
parameters.forEach(param => {
testParams[param] = ''; // Usar valores vazios para teste
});
// Fazer requisição de teste com per_page=1 para minimizar dados transferidos
testParams.per_page = '1';
testParams.page = '1';
await this.client.get(endpoint, testParams);
// Se chegou aqui, os parâmetros são suportados
this.parameterSupportCache.set(cacheKey, true);
return true;
}
catch (error) {
// Verificar se o erro é especificamente sobre parâmetros inválidos
if (error instanceof ErrorUtils_1.WordPressError) {
const errorMessage = error.message.toLowerCase();
const isParameterError = parameters.some(param => errorMessage.includes(param.toLowerCase()) &&
(errorMessage.includes('inválido') || errorMessage.includes('invalid')));
if (isParameterError) {
// Parâmetros não são suportados
this.parameterSupportCache.set(cacheKey, false);
return false;
}
}
// Para outros tipos de erro, assumir que os parâmetros são suportados
// (o erro pode ser por outras razões, como autenticação)
this.parameterSupportCache.set(cacheKey, true);
return true;
}
}
/**
* Filtra posts no lado do cliente quando a filtragem no servidor falha
* @param posts Posts a serem filtrados
* @param categories IDs das categorias para filtrar
* @param tags IDs das tags para filtrar
* @returns Posts filtrados
*/
filterPostsClientSide(posts, categories, tags) {
return posts.filter(post => {
// Filtrar por categorias se especificado
if (categories.length > 0) {
const postCategories = post.categories || [];
const hasMatchingCategory = categories.some(catId => postCategories.includes(catId));
if (!hasMatchingCategory) {
return false;
}
}
// Filtrar por tags se especificado
if (tags.length > 0) {
const postTags = post.tags || [];
const hasMatchingTag = tags.some(tagId => postTags.includes(tagId));
if (!hasMatchingTag) {
return false;
}
}
return true;
});
}
/**
* Cria uma mensagem de erro amigável quando um endpoint não está disponível
* @param endpoint Endpoint que não foi encontrado
* @param method Método HTTP
* @returns Mensagem de erro
*/
createEndpointNotAvailableError(endpoint, method = 'GET') {
const message = `WordPress REST API endpoint '${endpoint}' is not available or does not support the ${method} method.
Possible causes:
• The endpoint may not exist in your WordPress version
• Required plugins may not be installed or activated
• The WordPress REST API may be disabled
• The API version (${this.client.getApiVersion()}) may not support this endpoint
Suggestions:
• Verify that the WordPress REST API is enabled
• Check if required plugins are installed and active
• Try using a different API version if available
• Ensure your WordPress installation is up to date`;
return new ErrorUtils_1.WordPressError(message, ErrorUtils_1.WordPressErrorType.ROUTE_NOT_FOUND, 404);
}
/**
* Obtém posts do WordPress
* @param options Opções da consulta
* @returns Array de posts
*/
async getPosts(options = {}) {
const { page = 1, perPage = 10, status = 'publish', search = '', categories = [], tags = [], includeSeoMetadata = false, includeFaqs = false, includeCta = false, } = options;
try {
// Validar se o endpoint 'posts' está disponível
const isEndpointAvailable = await this.validateEndpointAvailability('posts', 'GET');
if (!isEndpointAvailable) {
throw this.createEndpointNotAvailableError('posts', 'GET');
}
// Montar parâmetros básicos da consulta
const params = {
page: page.toString(),
per_page: perPage.toString(),
status,
};
// Adicionar termo de busca se fornecido
if (search) {
params.search = search;
}
// Verificar se precisamos testar suporte a parâmetros de taxonomia
const needsTaxonomyParams = categories.length > 0 || tags.length > 0;
let useServerSideFiltering = true;
if (needsTaxonomyParams) {
// Testar suporte aos parâmetros categories e tags
const taxonomyParams = [];
if (categories.length > 0)
taxonomyParams.push('categories');
if (tags.length > 0)
taxonomyParams.push('tags');
useServerSideFiltering = await this.testParameterSupport('posts', taxonomyParams);
}
let posts;
if (useServerSideFiltering && needsTaxonomyParams) {
// Tentar filtragem no servidor primeiro
try {
// Adicionar filtro de categorias se fornecido
if (categories.length > 0) {
params.categories = categories.join(',');
}
// Adicionar filtro de tags se fornecido
if (tags.length > 0) {
params.tags = tags.join(',');
}
// Fazer a requisição com parâmetros de taxonomia
posts = await this.client.get('posts', params);
}
catch (serverError) {
// Verificar se o erro é especificamente sobre parâmetros inválidos
if (serverError instanceof ErrorUtils_1.WordPressError) {
const errorMessage = serverError.message.toLowerCase();
const isParameterError = ((errorMessage.includes('categories') || errorMessage.includes('tags')) &&
(errorMessage.includes('inválido') || errorMessage.includes('invalid') ||
errorMessage.includes('parâmetro')));
if (isParameterError) {
// Marcar parâmetros como não suportados no cache
const taxonomyParams = [];
if (categories.length > 0)
taxonomyParams.push('categories');
if (tags.length > 0)
taxonomyParams.push('tags');
const cacheKey = `posts_${taxonomyParams.join(',')}`;
this.parameterSupportCache.set(cacheKey, false);
// Fazer fallback para filtragem no cliente
useServerSideFiltering = false;
}
else {
// Re-lançar outros tipos de erro
throw serverError;
}
}
else {
throw serverError;
}
}
}
if (!useServerSideFiltering || !needsTaxonomyParams) {
// Fazer requisição sem parâmetros de taxonomia
const basicParams = { ...params };
delete basicParams.categories;
delete basicParams.tags;
if (!useServerSideFiltering && needsTaxonomyParams) {
// Para filtragem no cliente, buscar mais posts para garantir resultados suficientes
// Aumentar per_page temporariamente, mas limitar a um máximo razoável
const originalPerPage = parseInt(basicParams.per_page);
const maxFetchSize = Math.min(originalPerPage * 3, 100); // Máximo de 100 posts
basicParams.per_page = maxFetchSize.toString();
basicParams.page = '1'; // Sempre buscar da primeira página para filtragem
}
posts = await this.client.get('posts', basicParams);
// Aplicar filtragem no cliente se necessário
if (!useServerSideFiltering && needsTaxonomyParams && posts && Array.isArray(posts)) {
posts = this.filterPostsClientSide(posts, categories, tags);
// Aplicar paginação manual após filtragem
const startIndex = (page - 1) * perPage;
const endIndex = startIndex + perPage;
posts = posts.slice(startIndex, endIndex);
}
}
// Se não há posts, retornar array vazio
if (!posts || !Array.isArray(posts)) {
return [];
}
// Processar os posts e enriquecer com metadados conforme solicitado
const enrichedPosts = await this.enrichPosts(posts, {
includeSeoMetadata,
includeFaqs,
includeCta,
});
return enrichedPosts;
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to fetch WordPress posts: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Obtém páginas do WordPress
* @param options Opções da consulta
* @returns Array de páginas
*/
async getPages(options = {}) {
const { page = 1, perPage = 10, status = 'publish', search = '', categories = [], tags = [], includeSeoMetadata = false, includeFaqs = false, includeCta = false, } = options;
try {
// Validar se o endpoint 'pages' está disponível
const isEndpointAvailable = await this.validateEndpointAvailability('pages', 'GET');
if (!isEndpointAvailable) {
throw this.createEndpointNotAvailableError('pages', 'GET');
}
// Montar parâmetros básicos da consulta
const params = {
page: page.toString(),
per_page: perPage.toString(),
status,
};
// Adicionar termo de busca se fornecido
if (search) {
params.search = search;
}
// Verificar se precisamos testar suporte a parâmetros de taxonomia
// Nota: Páginas geralmente não suportam categories/tags, mas alguns temas/plugins podem habilitar
const needsTaxonomyParams = categories.length > 0 || tags.length > 0;
let useServerSideFiltering = true;
if (needsTaxonomyParams) {
// Testar suporte aos parâmetros categories e tags para páginas
const taxonomyParams = [];
if (categories.length > 0)
taxonomyParams.push('categories');
if (tags.length > 0)
taxonomyParams.push('tags');
useServerSideFiltering = await this.testParameterSupport('pages', taxonomyParams);
}
let pages;
if (useServerSideFiltering && needsTaxonomyParams) {
// Tentar filtragem no servidor primeiro
try {
// Adicionar filtro de categorias se fornecido
if (categories.length > 0) {
params.categories = categories.join(',');
}
// Adicionar filtro de tags se fornecido
if (tags.length > 0) {
params.tags = tags.join(',');
}
// Fazer a requisição com parâmetros de taxonomia
pages = await this.client.get('pages', params);
}
catch (serverError) {
// Verificar se o erro é especificamente sobre parâmetros inválidos
if (serverError instanceof ErrorUtils_1.WordPressError) {
const errorMessage = serverError.message.toLowerCase();
const isParameterError = ((errorMessage.includes('categories') || errorMessage.includes('tags')) &&
(errorMessage.includes('inválido') || errorMessage.includes('invalid') ||
errorMessage.includes('parâmetro')));
if (isParameterError) {
// Marcar parâmetros como não suportados no cache
const taxonomyParams = [];
if (categories.length > 0)
taxonomyParams.push('categories');
if (tags.length > 0)
taxonomyParams.push('tags');
const cacheKey = `pages_${taxonomyParams.join(',')}`;
this.parameterSupportCache.set(cacheKey, false);
// Fazer fallback para filtragem no cliente
useServerSideFiltering = false;
}
else {
// Re-lançar outros tipos de erro
throw serverError;
}
}
else {
throw serverError;
}
}
}
if (!useServerSideFiltering || !needsTaxonomyParams) {
// Fazer requisição sem parâmetros de taxonomia
const basicParams = { ...params };
delete basicParams.categories;
delete basicParams.tags;
if (!useServerSideFiltering && needsTaxonomyParams) {
// Para filtragem no cliente, buscar mais páginas para garantir resultados suficientes
const originalPerPage = parseInt(basicParams.per_page);
const maxFetchSize = Math.min(originalPerPage * 3, 100); // Máximo de 100 páginas
basicParams.per_page = maxFetchSize.toString();
basicParams.page = '1'; // Sempre buscar da primeira página para filtragem
}
pages = await this.client.get('pages', basicParams);
// Aplicar filtragem no cliente se necessário
if (!useServerSideFiltering && needsTaxonomyParams && pages && Array.isArray(pages)) {
pages = this.filterPostsClientSide(pages, categories, tags);
// Aplicar paginação manual após filtragem
const startIndex = (page - 1) * perPage;
const endIndex = startIndex + perPage;
pages = pages.slice(startIndex, endIndex);
}
}
// Se não há páginas, retornar array vazio
if (!pages || !Array.isArray(pages)) {
return [];
}
// Processar as páginas e enriquecer com metadados conforme solicitado
const enrichedPages = await this.enrichPosts(pages, {
includeSeoMetadata,
includeFaqs,
includeCta,
});
return enrichedPages;
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to fetch WordPress pages: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Obtém um post específico pelo ID
* @param id ID do post
* @param options Opções da consulta
* @returns Post ou null se não encontrado
*/
async getPost(id, options = {}) {
const { includeSeoMetadata = false, includeFaqs = false, includeCta = false, } = options;
try {
// Validar se o endpoint específico do post está disponível
const endpoint = `posts/${id}`;
const isEndpointAvailable = await this.validateEndpointAvailability(endpoint, 'GET');
if (!isEndpointAvailable) {
throw this.createEndpointNotAvailableError(endpoint, 'GET');
}
// Fazer a requisição
const post = await this.client.get(endpoint);
// Se o post não foi encontrado, retornar null
if (!post) {
return null;
}
// Processar o post e enriquecer com metadados conforme solicitado
const [enrichedPost] = await this.enrichPosts([post], {
includeSeoMetadata,
includeFaqs,
includeCta,
});
return enrichedPost;
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
// Se é um erro 404, melhorar a mensagem
if (error.type === ErrorUtils_1.WordPressErrorType.NOT_FOUND) {
throw new ErrorUtils_1.WordPressError(`Post with ID ${id} not found. Please verify the post ID exists and you have permission to access it.`, ErrorUtils_1.WordPressErrorType.NOT_FOUND, error.statusCode, error.originalError);
}
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to fetch WordPress post with ID ${id}: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Obtém uma página específica pelo ID
* @param id ID da página
* @param options Opções da consulta
* @returns Página ou null se não encontrada
*/
async getPage(id, options = {}) {
const { includeSeoMetadata = false, includeFaqs = false, includeCta = false, } = options;
try {
// Validar se o endpoint específico da página está disponível
const endpoint = `pages/${id}`;
const isEndpointAvailable = await this.validateEndpointAvailability(endpoint, 'GET');
if (!isEndpointAvailable) {
throw this.createEndpointNotAvailableError(endpoint, 'GET');
}
// Fazer a requisição
const page = await this.client.get(endpoint);
// Se a página não foi encontrada, retornar null
if (!page) {
return null;
}
// Processar a página e enriquecer com metadados conforme solicitado
const [enrichedPage] = await this.enrichPosts([page], {
includeSeoMetadata,
includeFaqs,
includeCta,
});
return enrichedPage;
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
// Se é um erro 404, melhorar a mensagem
if (error.type === ErrorUtils_1.WordPressErrorType.NOT_FOUND) {
throw new ErrorUtils_1.WordPressError(`Page with ID ${id} not found. Please verify the page ID exists and you have permission to access it.`, ErrorUtils_1.WordPressErrorType.NOT_FOUND, error.statusCode, error.originalError);
}
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to fetch WordPress page with ID ${id}: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Obtém categorias do WordPress
* @param options Opções da consulta
* @returns Array de categorias
*/
async getCategories(options = {}) {
const { page = 1, perPage = 10, search = '', } = options;
try {
// Validar se o endpoint 'categories' está disponível
const isEndpointAvailable = await this.validateEndpointAvailability('categories', 'GET');
if (!isEndpointAvailable) {
throw this.createEndpointNotAvailableError('categories', 'GET');
}
// Montar parâmetros da consulta
const params = {
page: page.toString(),
per_page: perPage.toString(),
};
// Adicionar termo de busca se fornecido
if (search) {
params.search = search;
}
// Fazer a requisição
const categories = await this.client.get('categories', params);
// Se não há categorias, retornar array vazio
if (!categories || !Array.isArray(categories)) {
return [];
}
// Mapear os dados para o formato da interface
return categories.map((category) => ({
id: category.id,
name: category.name,
slug: category.slug,
}));
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to fetch WordPress categories: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Obtém tags do WordPress
* @param options Opções da consulta
* @returns Array de tags
*/
async getTags(options = {}) {
const { page = 1, perPage = 10, search = '', } = options;
try {
// Validar se o endpoint 'tags' está disponível
const isEndpointAvailable = await this.validateEndpointAvailability('tags', 'GET');
if (!isEndpointAvailable) {
throw this.createEndpointNotAvailableError('tags', 'GET');
}
// Montar parâmetros da consulta
const params = {
page: page.toString(),
per_page: perPage.toString(),
};
// Adicionar termo de busca se fornecido
if (search) {
params.search = search;
}
// Fazer a requisição
const tags = await this.client.get('tags', params);
// Se não há tags, retornar array vazio
if (!tags || !Array.isArray(tags)) {
return [];
}
// Mapear os dados para o formato da interface
return tags.map((tag) => ({
id: tag.id,
name: tag.name,
slug: tag.slug,
}));
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to fetch WordPress tags: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Enriquece os posts com metadados do AI GROWTH - SEO WP
* @param posts Posts a serem enriquecidos
* @param options Opções de enriquecimento
* @returns Posts enriquecidos
*/
async enrichPosts(posts, options) {
const { includeSeoMetadata, includeFaqs, includeCta } = options;
// Mapear os posts para o formato da interface
const mappedPosts = posts.map((post) => {
var _a, _b, _c;
return ({
id: post.id,
title: ((_a = post.title) === null || _a === void 0 ? void 0 : _a.rendered) || '',
content: ((_b = post.content) === null || _b === void 0 ? void 0 : _b.rendered) || '',
status: post.status || 'publish',
categories: post.categories || [],
tags: post.tags || [],
image_url: post.featured_media && typeof post.featured_media === 'number'
? '' // Não temos acesso direto à URL da imagem pelo ID
: ((_c = post.featured_media) === null || _c === void 0 ? void 0 : _c.source_url) || '',
});
});
// Se não é para incluir metadados, retorna os posts mapeados
if (!includeSeoMetadata && !includeFaqs && !includeCta) {
return mappedPosts;
}
// Verificar disponibilidade do plugin
const pluginInfo = await this.seoService.checkPluginAvailability();
const isPluginActive = pluginInfo.status === 'active';
console.log('[ContentService] enrichPosts - Plugin status:', {
isPluginActive,
pluginInfo,
includeSeoMetadata,
includeFaqs,
includeCta
});
// Enriquecer os posts com metadados
const enrichedPosts = await Promise.all(mappedPosts.map(async (post) => {
var _a;
const metadata = {};
const originalPost = posts.find(p => p.id === post.id);
// Obter metadados SEO se solicitado
if (includeSeoMetadata && post.id) {
if (isPluginActive) {
// Plugin ativo - usar API do plugin
try {
const seoMetadata = await this.seoService.getPostSeoMetadata(post.id);
if (seoMetadata) {
metadata.meta_title = seoMetadata.meta_title;
metadata.meta_description = seoMetadata.meta_description;
metadata.meta_keywords = seoMetadata.meta_keywords;
metadata.og_title = seoMetadata.og_title;
metadata.og_description = seoMetadata.og_description;
metadata.twitter_title = seoMetadata.twitter_title;
metadata.twitter_description = seoMetadata.twitter_description;
}
}
catch (error) {
console.error('[ContentService] Error fetching SEO metadata from plugin:', error);
}
}
else {
// Plugin não ativo - extrair meta fields do response do WordPress
console.log('[ContentService] Plugin not active, extracting meta fields from WordPress response');
if (originalPost === null || originalPost === void 0 ? void 0 : originalPost.meta) {
console.log('[ContentService] Original post meta fields:', {
meta_title: originalPost.meta._ai_growth_seo_meta_title,
meta_description: originalPost.meta._ai_growth_seo_meta_description,
meta_keywords: originalPost.meta._ai_growth_seo_meta_keywords,
og_title: originalPost.meta._ai_growth_seo_og_title,
og_description: originalPost.meta._ai_growth_seo_og_description,
twitter_title: originalPost.meta._ai_growth_seo_twitter_title,
twitter_description: originalPost.meta._ai_growth_seo_twitter_description
});
// Extrair meta fields do response do WordPress
metadata.meta_title = originalPost.meta._ai_growth_seo_meta_title || '';
metadata.meta_description = originalPost.meta._ai_growth_seo_meta_description || '';
metadata.meta_keywords = originalPost.meta._ai_growth_seo_meta_keywords || '';
metadata.og_title = originalPost.meta._ai_growth_seo_og_title || '';
metadata.og_description = originalPost.meta._ai_growth_seo_og_description || '';
metadata.twitter_title = originalPost.meta._ai_growth_seo_twitter_title || '';
metadata.twitter_description = originalPost.meta._ai_growth_seo_twitter_description || '';
}
else {
console.log('[ContentService] No meta fields found in original post');
}
}
}
// Obter FAQs se solicitado
if (includeFaqs && post.id) {
if (isPluginActive) {
try {
const faqs = await this.faqService.getPostFaqs(post.id);
if (faqs && faqs.length > 0) {
metadata.faq = faqs;
}
}
catch (error) {
console.error('[ContentService] Error fetching FAQs:', error);
}
}
else {
// Extrair FAQs do response do WordPress se disponível
if ((_a = originalPost === null || originalPost === void 0 ? void 0 : originalPost.meta) === null || _a === void 0 ? void 0 : _a._ai_growth_seo_faq_items) {
metadata.faq = originalPost.meta._ai_growth_seo_faq_items;
}
}
}
// Obter CTA se solicitado
if (includeCta && post.id) {
if (isPluginActive) {
try {
const cta = await this.ctaService.getPostCta(post.id);
if (cta) {
metadata.cta = cta;
}
}
catch (error) {
console.error('[ContentService] Error fetching CTA:', error);
}
}
else {
// Extrair CTA do response do WordPress se disponível
if (originalPost === null || originalPost === void 0 ? void 0 : originalPost.meta) {
const ctaData = {
text: originalPost.meta._ai_growth_seo_cta_button_text || '',
url: originalPost.meta._ai_growth_seo_cta_link_url || '',
style: originalPost.meta._ai_growth_seo_cta_button_style || 'primary',
target: originalPost.meta._ai_growth_seo_cta_target || '_self',
enabled: originalPost.meta._ai_growth_seo_cta_enabled || false,
position: originalPost.meta._ai_growth_seo_cta_position || 'bottom',
description: originalPost.meta._ai_growth_seo_cta_description || '',
icon: originalPost.meta._ai_growth_seo_cta_icon || ''
};
// Só incluir CTA se tiver dados relevantes
if (ctaData.text || ctaData.url) {
metadata.cta = ctaData;
}
}
}
}
console.log('[ContentService] Final metadata for post', post.id, ':', metadata);
// Adicionar metadados ao post
return { ...post, ...metadata };
}));
return enrichedPosts;
}
}
exports.ContentService = ContentService;
//# sourceMappingURL=ContentService.js.map