@mixpeek/contentful 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (2026-02-11)
4
+
5
+ - Initial release
6
+ - WebhookHandler, ContentEnricher, ContentfulClient modules
7
+ - Mixpeek API client with retry logic
8
+ - In-memory LRU cache
9
+ - Unit, E2E, and live API tests
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mixpeek
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # @mixpeek/contentful
2
+
3
+ Contentful integration for Mixpeek — webhook handling, content enrichment, and management API integration
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @mixpeek/contentful contentful-management
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```js
14
+ import webhookHandler from '@mixpeek/contentful';
15
+
16
+ const instance = webhookHandler({
17
+ apiKey: process.env.MIXPEEK_API_KEY
18
+ });
19
+ ```
20
+
21
+ ## Modules
22
+
23
+ ### WebhookHandler
24
+
25
+ Handles Contentful webhooks (entry publish/unpublish/archive) and triggers enrichment
26
+
27
+ ```js
28
+ import { createWebhookHandler } from '@mixpeek/contentful';
29
+
30
+ const webhookHandler = createWebhookHandler({
31
+ apiKey: process.env.MIXPEEK_API_KEY
32
+ });
33
+ ```
34
+
35
+ ### ContentEnricher
36
+
37
+ Enriches Contentful entries with Mixpeek multimodal analysis stored in custom fields
38
+
39
+ ```js
40
+ import { createContentEnricher } from '@mixpeek/contentful';
41
+
42
+ const contentEnricher = createContentEnricher({
43
+ apiKey: process.env.MIXPEEK_API_KEY
44
+ });
45
+ ```
46
+
47
+ ### ContentfulClient
48
+
49
+ Contentful Management API client for reading/writing enrichment data
50
+
51
+ ```js
52
+ import { createContentfulClient } from '@mixpeek/contentful';
53
+
54
+ const contentfulClient = createContentfulClient({
55
+ apiKey: process.env.MIXPEEK_API_KEY
56
+ });
57
+ ```
58
+
59
+ ## Testing
60
+
61
+ ```bash
62
+ npm test # Unit tests
63
+ npm run test:e2e # End-to-end tests
64
+ npm run test:live # Live API tests (requires MIXPEEK_API_KEY)
65
+ npm run test:coverage # Coverage report
66
+ ```
67
+
68
+ ## License
69
+
70
+ MIT
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @mixpeek/contentful — Mixpeek API Client
3
+ *
4
+ * HTTP client for Mixpeek API integration with retry logic and timeout handling.
5
+ */
6
+
7
+ import {
8
+ API_ENDPOINT, API_VERSION, DEFAULT_TIMEOUT,
9
+ RETRY_ATTEMPTS, RETRY_DELAY, ERROR_CODES, HEADERS
10
+ } from '../config/constants.js';
11
+ import { getLogger } from '../utils/logger.js';
12
+
13
+ class MixpeekClient {
14
+ /**
15
+ * @param {Object} config
16
+ * @param {string} config.apiKey - Mixpeek API key
17
+ * @param {string} [config.endpoint] - API endpoint
18
+ * @param {number} [config.timeout] - Request timeout in ms
19
+ * @param {boolean} [config.debug] - Enable debug logging
20
+ */
21
+ constructor(config) {
22
+ if (!config.apiKey) throw new Error('API key is required');
23
+
24
+ this.apiKey = config.apiKey;
25
+ this.endpoint = (config.endpoint || API_ENDPOINT).replace(/\/$/, '');
26
+ this.timeout = config.timeout || DEFAULT_TIMEOUT;
27
+ this.logger = getLogger({ debug: config.debug });
28
+ }
29
+
30
+ async request(method, path, body = null) {
31
+ const url = `${this.endpoint}/${API_VERSION}${path}`;
32
+ const headers = {
33
+ 'Authorization': `Bearer ${this.apiKey}`,
34
+ 'Content-Type': HEADERS.CONTENT_TYPE,
35
+ 'Accept': HEADERS.ACCEPT,
36
+ 'User-Agent': HEADERS.USER_AGENT
37
+ };
38
+
39
+ let lastError;
40
+ for (let attempt = 0; attempt <= RETRY_ATTEMPTS; attempt++) {
41
+ try {
42
+ const controller = new AbortController();
43
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
44
+
45
+ this.logger.debug(`API ${method} ${path} (attempt ${attempt + 1})`);
46
+
47
+ const response = await fetch(url, {
48
+ method,
49
+ headers,
50
+ body: body ? JSON.stringify(body) : null,
51
+ signal: controller.signal
52
+ });
53
+
54
+ clearTimeout(timeoutId);
55
+
56
+ if (!response.ok) {
57
+ const errorBody = await response.text();
58
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
59
+ }
60
+
61
+ return await response.json();
62
+ } catch (error) {
63
+ lastError = error;
64
+ if (error.name === 'AbortError') {
65
+ lastError = new Error(`Request timeout after ${this.timeout}ms`);
66
+ lastError.code = ERROR_CODES.TIMEOUT;
67
+ }
68
+ if (attempt < RETRY_ATTEMPTS) {
69
+ await new Promise(r => setTimeout(r, RETRY_DELAY));
70
+ }
71
+ }
72
+ }
73
+
74
+ this.logger.error('API request failed after retries:', lastError.message);
75
+ throw lastError;
76
+ }
77
+
78
+ async healthCheck() {
79
+ try {
80
+ const start = Date.now();
81
+ const response = await this.request('GET', '/health');
82
+ return { status: 'healthy', latency: Date.now() - start, timestamp: new Date().toISOString(), response };
83
+ } catch (error) {
84
+ return { status: 'unhealthy', error: error.message, timestamp: new Date().toISOString() };
85
+ }
86
+ }
87
+
88
+ async search(query, options = {}) {
89
+ return this.request('POST', '/features/search', { query, ...options });
90
+ }
91
+
92
+ async getDocument(collectionId, documentId) {
93
+ return this.request('GET', `/collections/${collectionId}/documents/${documentId}`);
94
+ }
95
+
96
+ async createDocument(collectionId, payload) {
97
+ return this.request('POST', `/collections/${collectionId}/documents`, payload);
98
+ }
99
+
100
+ async listDocuments(collectionId, options = {}) {
101
+ const params = new URLSearchParams(options).toString();
102
+ return this.request('GET', `/collections/${collectionId}/documents${params ? '?' + params : ''}`);
103
+ }
104
+ }
105
+
106
+ export function createClient(config) {
107
+ return new MixpeekClient(config);
108
+ }
109
+
110
+ export { MixpeekClient };
111
+ export default { createClient, MixpeekClient };
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @mixpeek/contentful — Cache Manager
3
+ *
4
+ * In-memory LRU caching with TTL support.
5
+ */
6
+
7
+ import { DEFAULT_CACHE_TTL, MAX_CACHE_ITEMS, CACHE_KEY_PREFIX } from '../config/constants.js';
8
+ import { getLogger } from '../utils/logger.js';
9
+
10
+ class CacheManager {
11
+ constructor(options = {}) {
12
+ this.ttl = (options.ttl || DEFAULT_CACHE_TTL) * 1000;
13
+ this.maxItems = options.maxItems || MAX_CACHE_ITEMS;
14
+ this.cache = new Map();
15
+ this.stats = { hits: 0, misses: 0, sets: 0, evictions: 0 };
16
+ this.logger = getLogger({ debug: options.debug });
17
+ this.cleanupInterval = setInterval(() => this.prune(), 60000);
18
+ if (this.cleanupInterval.unref) this.cleanupInterval.unref();
19
+ }
20
+
21
+ _prefixKey(key) { return `${CACHE_KEY_PREFIX}${key}`; }
22
+
23
+ get(key) {
24
+ const item = this.cache.get(this._prefixKey(key));
25
+ if (!item) { this.stats.misses++; return null; }
26
+ if (Date.now() > item.expiry) { this.cache.delete(this._prefixKey(key)); this.stats.misses++; return null; }
27
+ this.stats.hits++;
28
+ item.lastAccess = Date.now();
29
+ return item.data;
30
+ }
31
+
32
+ set(key, data, ttl = null) {
33
+ if (this.cache.size >= this.maxItems) this._evictLRU();
34
+ this.cache.set(this._prefixKey(key), {
35
+ data, expiry: Date.now() + (ttl ? ttl * 1000 : this.ttl),
36
+ createdAt: Date.now(), lastAccess: Date.now()
37
+ });
38
+ this.stats.sets++;
39
+ }
40
+
41
+ has(key) {
42
+ const item = this.cache.get(this._prefixKey(key));
43
+ if (!item) return false;
44
+ if (Date.now() > item.expiry) { this.cache.delete(this._prefixKey(key)); return false; }
45
+ return true;
46
+ }
47
+
48
+ delete(key) { return this.cache.delete(this._prefixKey(key)); }
49
+ clear() { this.cache.clear(); }
50
+
51
+ prune() {
52
+ const now = Date.now();
53
+ let pruned = 0;
54
+ for (const [key, item] of this.cache.entries()) {
55
+ if (now > item.expiry) { this.cache.delete(key); pruned++; }
56
+ }
57
+ return pruned;
58
+ }
59
+
60
+ _evictLRU() {
61
+ let oldestKey = null, oldestAccess = Infinity;
62
+ for (const [key, item] of this.cache.entries()) {
63
+ if (item.lastAccess < oldestAccess) { oldestAccess = item.lastAccess; oldestKey = key; }
64
+ }
65
+ if (oldestKey) { this.cache.delete(oldestKey); this.stats.evictions++; }
66
+ }
67
+
68
+ getStats() {
69
+ const total = this.stats.hits + this.stats.misses;
70
+ return {
71
+ size: this.cache.size, maxSize: this.maxItems,
72
+ hits: this.stats.hits, misses: this.stats.misses,
73
+ hitRate: total > 0 ? Math.round((this.stats.hits / total) * 10000) / 100 : 0,
74
+ sets: this.stats.sets, evictions: this.stats.evictions, ttlSeconds: this.ttl / 1000
75
+ };
76
+ }
77
+
78
+ resetStats() { this.stats = { hits: 0, misses: 0, sets: 0, evictions: 0 }; }
79
+
80
+ destroy() {
81
+ if (this.cleanupInterval) { clearInterval(this.cleanupInterval); this.cleanupInterval = null; }
82
+ this.cache.clear();
83
+ }
84
+
85
+ get size() { return this.cache.size; }
86
+ }
87
+
88
+ export function createCacheManager(options = {}) { return new CacheManager(options); }
89
+ export { CacheManager };
90
+ export default { createCacheManager, CacheManager };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @mixpeek/contentful — Configuration Constants
3
+ */
4
+
5
+ // API Configuration
6
+ export const API_ENDPOINT = 'https://api.mixpeek.com';
7
+ export const API_VERSION = 'v1';
8
+ export const DEFAULT_TIMEOUT = 30000; // milliseconds
9
+ export const MAX_TIMEOUT = 60000;
10
+ export const RETRY_ATTEMPTS = 1;
11
+ export const RETRY_DELAY = 100; // milliseconds
12
+
13
+ // Cache Configuration
14
+ export const DEFAULT_CACHE_TTL = 300; // seconds (5 minutes)
15
+ export const MAX_CACHE_ITEMS = 1000;
16
+ export const CACHE_KEY_PREFIX = 'mixpeek_ctfl_';
17
+
18
+ // Error Codes
19
+ export const ERROR_CODES = {
20
+ API_ERROR: 'MIXPEEK_API_ERROR',
21
+ TIMEOUT: 'MIXPEEK_TIMEOUT',
22
+ INVALID_CONFIG: 'MIXPEEK_INVALID_CONFIG',
23
+ INVALID_REQUEST: 'MIXPEEK_INVALID_REQUEST',
24
+ RATE_LIMITED: 'MIXPEEK_RATE_LIMITED',
25
+ CACHE_ERROR: 'MIXPEEK_CACHE_ERROR'
26
+ };
27
+
28
+ // HTTP Headers
29
+ export const HEADERS = {
30
+ CONTENT_TYPE: 'application/json',
31
+ ACCEPT: 'application/json',
32
+ USER_AGENT: 'Mixpeek-Contentful-Connector/1.0.0'
33
+ };
34
+
35
+ // Default Configuration
36
+ export const DEFAULT_CONFIG = {
37
+ endpoint: API_ENDPOINT,
38
+ timeout: DEFAULT_TIMEOUT,
39
+ cacheTTL: DEFAULT_CACHE_TTL,
40
+ enableCache: true,
41
+ debug: false
42
+ };
43
+
44
+ export default {
45
+ API_ENDPOINT, API_VERSION, DEFAULT_TIMEOUT, MAX_TIMEOUT,
46
+ RETRY_ATTEMPTS, RETRY_DELAY, DEFAULT_CACHE_TTL, MAX_CACHE_ITEMS,
47
+ CACHE_KEY_PREFIX, ERROR_CODES, HEADERS, DEFAULT_CONFIG
48
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+ let modulePromise = null;
3
+ function getModule() { if (!modulePromise) modulePromise = import('./index.js'); return modulePromise; }
4
+ module.exports = {
5
+ async createWebhookHandler(config) { const mod = await getModule(); return new mod.WebhookHandler(config); },
6
+ getModule,
7
+ version: '1.0.0'
8
+ };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @mixpeek/contentful — TypeScript declarations
3
+ */
4
+
5
+ export interface ConnectorConfig {
6
+ apiKey: string;
7
+ endpoint?: string;
8
+ timeout?: number;
9
+ cacheTTL?: number;
10
+ enableCache?: boolean;
11
+ debug?: boolean;
12
+ }
13
+
14
+ export interface MetricsResult {
15
+ requests: number;
16
+ errors: number;
17
+ totalLatencyMs: number;
18
+ avgLatencyMs: number;
19
+ cache: { size: number; hits: number; misses: number; hitRate: number } | null;
20
+ }
21
+
22
+ export declare class WebhookHandler {
23
+ constructor(config: ConnectorConfig);
24
+ handleWebhook(...args: any[]): any;
25
+ verifySignature(...args: any[]): any;
26
+ registerWebhook(...args: any[]): any;
27
+ listWebhooks(...args: any[]): any;
28
+ deleteWebhook(...args: any[]): any;
29
+ getMetrics(): MetricsResult;
30
+ resetMetrics(): void;
31
+ destroy(): void;
32
+ }
33
+
34
+ export declare class ContentEnricher {
35
+ constructor(config: ConnectorConfig);
36
+ enrichEntry(...args: any[]): any;
37
+ enrichAsset(...args: any[]): any;
38
+ enrichBatch(...args: any[]): any;
39
+ getEnrichment(...args: any[]): any;
40
+ writeField(...args: any[]): any;
41
+ getMetrics(): MetricsResult;
42
+ resetMetrics(): void;
43
+ destroy(): void;
44
+ }
45
+
46
+ export declare class ContentfulClient {
47
+ constructor(config: ConnectorConfig);
48
+ getEntry(...args: any[]): any;
49
+ getEntries(...args: any[]): any;
50
+ updateEntry(...args: any[]): any;
51
+ getAsset(...args: any[]): any;
52
+ publishEntry(...args: any[]): any;
53
+ getMetrics(): MetricsResult;
54
+ resetMetrics(): void;
55
+ destroy(): void;
56
+ }
57
+
58
+ export declare function createWebhookHandler(config: ConnectorConfig): WebhookHandler;
59
+ export declare function createContentEnricher(config: ConnectorConfig): ContentEnricher;
60
+ export declare function createContentfulClient(config: ConnectorConfig): ContentfulClient;
61
+
62
+ export declare class MixpeekClient {
63
+ constructor(config: ConnectorConfig);
64
+ request(method: string, path: string, body?: any): Promise<any>;
65
+ healthCheck(): Promise<{ status: string; latency?: number; error?: string }>;
66
+ search(query: any, options?: any): Promise<any>;
67
+ }
68
+
69
+ export declare class CacheManager {
70
+ constructor(options?: { ttl?: number; maxItems?: number; debug?: boolean });
71
+ get(key: string): any | null;
72
+ set(key: string, value: any, ttl?: number): void;
73
+ has(key: string): boolean;
74
+ delete(key: string): boolean;
75
+ clear(): void;
76
+ getStats(): { size: number; hits: number; misses: number; hitRate: number };
77
+ destroy(): void;
78
+ }
79
+
80
+ export declare function createClient(config: ConnectorConfig): MixpeekClient;
81
+ export declare function createCacheManager(options?: any): CacheManager;
package/dist/index.js ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @mixpeek/contentful — Mixpeek Contentful Connector
3
+ *
4
+ * Contentful integration for Mixpeek — webhook handling, content enrichment, and management API integration
5
+ *
6
+ * @module @mixpeek/contentful
7
+ * @version 1.0.0
8
+ */
9
+
10
+ // Modules
11
+ export { createWebhookHandler, WebhookHandler } from './modules/webhookHandler.js';
12
+ export { createContentEnricher, ContentEnricher } from './modules/contentEnricher.js';
13
+ export { createContentfulClient, ContentfulClient } from './modules/contentfulClient.js';
14
+
15
+ // API client
16
+ export { createClient, MixpeekClient } from './api/mixpeekClient.js';
17
+
18
+ // Cache manager
19
+ export { createCacheManager, CacheManager } from './cache/cacheManager.js';
20
+
21
+ // Utilities
22
+ export {
23
+ generateId,
24
+ createCacheKey,
25
+ sanitizeText,
26
+ deepMerge,
27
+ isValidUrl,
28
+ extractDomain
29
+ } from './utils/helpers.js';
30
+
31
+ // Logger
32
+ export { getLogger, createLogger, Logger, LOG_LEVELS } from './utils/logger.js';
33
+
34
+ // Constants
35
+ export {
36
+ API_ENDPOINT,
37
+ API_VERSION,
38
+ DEFAULT_TIMEOUT,
39
+ DEFAULT_CACHE_TTL,
40
+ ERROR_CODES,
41
+ DEFAULT_CONFIG
42
+ } from './config/constants.js';
43
+
44
+ // Default export
45
+ import { createWebhookHandler } from './modules/webhookHandler.js';
46
+ export default createWebhookHandler;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @mixpeek/contentful — ContentEnricher
3
+ *
4
+ * Enriches Contentful entries with Mixpeek multimodal analysis stored in custom fields
5
+ */
6
+
7
+ import { createClient } from '../api/mixpeekClient.js';
8
+ import { createCacheManager } from '../cache/cacheManager.js';
9
+ import { getLogger } from '../utils/logger.js';
10
+ import { DEFAULT_CONFIG } from '../config/constants.js';
11
+
12
+ class ContentEnricher {
13
+ /**
14
+ * @param {Object} config
15
+ * @param {string} config.apiKey - Mixpeek API key
16
+ * @param {string} [config.endpoint] - API endpoint
17
+ * @param {number} [config.timeout] - Request timeout in ms
18
+ * @param {number} [config.cacheTTL] - Cache TTL in seconds
19
+ * @param {boolean} [config.enableCache] - Enable caching
20
+ * @param {boolean} [config.debug] - Enable debug logging
21
+ */
22
+ constructor(config = {}) {
23
+ if (!config.apiKey) throw new Error('apiKey is required for ContentEnricher');
24
+
25
+ this.config = { ...DEFAULT_CONFIG, ...config };
26
+ this.client = createClient({
27
+ apiKey: config.apiKey,
28
+ endpoint: this.config.endpoint,
29
+ timeout: this.config.timeout,
30
+ debug: this.config.debug
31
+ });
32
+ this.cache = this.config.enableCache ? createCacheManager({ ttl: this.config.cacheTTL, debug: this.config.debug }) : null;
33
+ this.logger = getLogger({ debug: this.config.debug });
34
+ this.metrics = { requests: 0, errors: 0, totalLatencyMs: 0 };
35
+ this.logger.info('ContentEnricher initialized');
36
+ }
37
+
38
+ async enrichEntry(...args) {
39
+ this.logger.debug('ContentEnricher.enrichEntry called');
40
+ // TODO: Implement enrichEntry
41
+ throw new Error('ContentEnricher.enrichEntry not yet implemented');
42
+ }
43
+
44
+ async enrichAsset(...args) {
45
+ this.logger.debug('ContentEnricher.enrichAsset called');
46
+ // TODO: Implement enrichAsset
47
+ throw new Error('ContentEnricher.enrichAsset not yet implemented');
48
+ }
49
+
50
+ async enrichBatch(...args) {
51
+ this.logger.debug('ContentEnricher.enrichBatch called');
52
+ // TODO: Implement enrichBatch
53
+ throw new Error('ContentEnricher.enrichBatch not yet implemented');
54
+ }
55
+
56
+ async getEnrichment(...args) {
57
+ this.logger.debug('ContentEnricher.getEnrichment called');
58
+ // TODO: Implement getEnrichment
59
+ throw new Error('ContentEnricher.getEnrichment not yet implemented');
60
+ }
61
+
62
+ async writeField(...args) {
63
+ this.logger.debug('ContentEnricher.writeField called');
64
+ // TODO: Implement writeField
65
+ throw new Error('ContentEnricher.writeField not yet implemented');
66
+ }
67
+
68
+ getMetrics() {
69
+ return {
70
+ ...this.metrics,
71
+ avgLatencyMs: this.metrics.requests > 0 ? this.metrics.totalLatencyMs / this.metrics.requests : 0,
72
+ cache: this.cache ? this.cache.getStats() : null
73
+ };
74
+ }
75
+
76
+ resetMetrics() {
77
+ this.metrics = { requests: 0, errors: 0, totalLatencyMs: 0 };
78
+ if (this.cache) this.cache.resetStats();
79
+ }
80
+
81
+ destroy() {
82
+ if (this.cache) this.cache.destroy();
83
+ this.logger.info('ContentEnricher destroyed');
84
+ }
85
+ }
86
+
87
+ export function createContentEnricher(config) {
88
+ return new ContentEnricher(config);
89
+ }
90
+
91
+ export { ContentEnricher };
92
+ export default { createContentEnricher, ContentEnricher };
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @mixpeek/contentful — ContentfulClient
3
+ *
4
+ * Contentful Management API client for reading/writing enrichment data
5
+ */
6
+
7
+ import { createClient } from '../api/mixpeekClient.js';
8
+ import { createCacheManager } from '../cache/cacheManager.js';
9
+ import { getLogger } from '../utils/logger.js';
10
+ import { DEFAULT_CONFIG } from '../config/constants.js';
11
+
12
+ class ContentfulClient {
13
+ /**
14
+ * @param {Object} config
15
+ * @param {string} config.apiKey - Mixpeek API key
16
+ * @param {string} [config.endpoint] - API endpoint
17
+ * @param {number} [config.timeout] - Request timeout in ms
18
+ * @param {number} [config.cacheTTL] - Cache TTL in seconds
19
+ * @param {boolean} [config.enableCache] - Enable caching
20
+ * @param {boolean} [config.debug] - Enable debug logging
21
+ */
22
+ constructor(config = {}) {
23
+ if (!config.apiKey) throw new Error('apiKey is required for ContentfulClient');
24
+
25
+ this.config = { ...DEFAULT_CONFIG, ...config };
26
+ this.client = createClient({
27
+ apiKey: config.apiKey,
28
+ endpoint: this.config.endpoint,
29
+ timeout: this.config.timeout,
30
+ debug: this.config.debug
31
+ });
32
+ this.cache = this.config.enableCache ? createCacheManager({ ttl: this.config.cacheTTL, debug: this.config.debug }) : null;
33
+ this.logger = getLogger({ debug: this.config.debug });
34
+ this.metrics = { requests: 0, errors: 0, totalLatencyMs: 0 };
35
+ this.logger.info('ContentfulClient initialized');
36
+ }
37
+
38
+ async getEntry(...args) {
39
+ this.logger.debug('ContentfulClient.getEntry called');
40
+ // TODO: Implement getEntry
41
+ throw new Error('ContentfulClient.getEntry not yet implemented');
42
+ }
43
+
44
+ async getEntries(...args) {
45
+ this.logger.debug('ContentfulClient.getEntries called');
46
+ // TODO: Implement getEntries
47
+ throw new Error('ContentfulClient.getEntries not yet implemented');
48
+ }
49
+
50
+ async updateEntry(...args) {
51
+ this.logger.debug('ContentfulClient.updateEntry called');
52
+ // TODO: Implement updateEntry
53
+ throw new Error('ContentfulClient.updateEntry not yet implemented');
54
+ }
55
+
56
+ async getAsset(...args) {
57
+ this.logger.debug('ContentfulClient.getAsset called');
58
+ // TODO: Implement getAsset
59
+ throw new Error('ContentfulClient.getAsset not yet implemented');
60
+ }
61
+
62
+ async publishEntry(...args) {
63
+ this.logger.debug('ContentfulClient.publishEntry called');
64
+ // TODO: Implement publishEntry
65
+ throw new Error('ContentfulClient.publishEntry not yet implemented');
66
+ }
67
+
68
+ getMetrics() {
69
+ return {
70
+ ...this.metrics,
71
+ avgLatencyMs: this.metrics.requests > 0 ? this.metrics.totalLatencyMs / this.metrics.requests : 0,
72
+ cache: this.cache ? this.cache.getStats() : null
73
+ };
74
+ }
75
+
76
+ resetMetrics() {
77
+ this.metrics = { requests: 0, errors: 0, totalLatencyMs: 0 };
78
+ if (this.cache) this.cache.resetStats();
79
+ }
80
+
81
+ destroy() {
82
+ if (this.cache) this.cache.destroy();
83
+ this.logger.info('ContentfulClient destroyed');
84
+ }
85
+ }
86
+
87
+ export function createContentfulClient(config) {
88
+ return new ContentfulClient(config);
89
+ }
90
+
91
+ export { ContentfulClient };
92
+ export default { createContentfulClient, ContentfulClient };