UNPKG

@hotmeshio/hotmesh

Version:

Permanent-Memory Workflows & AI Agents

114 lines (113 loc) 3.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getProviderSpecificFeatures = exports.isNotificationsEnabled = exports.trimStream = exports.getStreamDepths = exports.getStreamDepth = exports.getStreamStats = void 0; /** * Get statistics for a specific stream. * Returns message count and other metrics. */ async function getStreamStats(client, tableName, streamName, logger) { try { const res = await client.query(`SELECT COUNT(*) AS available_count FROM ${tableName} WHERE stream_name = $1 AND expired_at IS NULL`, [streamName]); return { messageCount: parseInt(res.rows[0].available_count, 10), }; } catch (error) { logger.error(`postgres-stream-stats-error-${streamName}`, { error }); throw error; } } exports.getStreamStats = getStreamStats; /** * Get the depth (message count) for a specific stream. */ async function getStreamDepth(client, tableName, streamName, logger) { const stats = await getStreamStats(client, tableName, streamName, logger); return stats.messageCount; } exports.getStreamDepth = getStreamDepth; /** * Get depths for multiple streams in a single query. * More efficient than calling getStreamDepth multiple times. */ async function getStreamDepths(client, tableName, streamNames, logger) { try { const streams = streamNames.map((s) => s.stream); const res = await client.query(`SELECT stream_name, COUNT(*) AS count FROM ${tableName} WHERE stream_name = ANY($1::text[]) GROUP BY stream_name`, [streams]); const result = res.rows.map((row) => ({ stream: row.stream_name, depth: parseInt(row.count, 10), })); return result; } catch (error) { logger.error('postgres-stream-depth-error', { error }); throw error; } } exports.getStreamDepths = getStreamDepths; /** * Trim (soft delete) messages from a stream based on age or count. * Returns the number of messages expired. */ async function trimStream(client, tableName, streamName, options, logger) { try { let expiredCount = 0; if (options.maxLen !== undefined) { const res = await client.query(`WITH to_expire AS ( SELECT id FROM ${tableName} WHERE stream_name = $1 ORDER BY id ASC OFFSET $2 ) UPDATE ${tableName} SET expired_at = NOW() WHERE id IN (SELECT id FROM to_expire)`, [streamName, options.maxLen]); expiredCount += res.rowCount; } if (options.maxAge !== undefined) { const res = await client.query(`UPDATE ${tableName} SET expired_at = NOW() WHERE stream_name = $1 AND created_at < NOW() - INTERVAL '${options.maxAge} milliseconds'`, [streamName]); expiredCount += res.rowCount; } return expiredCount; } catch (error) { logger.error(`postgres-stream-trim-error-${streamName}`, { error }); throw error; } } exports.trimStream = trimStream; /** * Check if notifications are enabled for the provider. */ function isNotificationsEnabled(config = {}) { // Allow override via environment variable if (process.env.HOTMESH_POSTGRES_DISABLE_NOTIFICATIONS === 'true') { return false; } return config?.postgres?.enableNotifications !== false; // Default: true } exports.isNotificationsEnabled = isNotificationsEnabled; /** * Get provider-specific feature flags and capabilities. */ function getProviderSpecificFeatures(config = {}) { return { supportsBatching: true, supportsDeadLetterQueue: false, supportsOrdering: true, supportsTrimming: true, supportsRetry: false, supportsNotifications: isNotificationsEnabled(config), maxMessageSize: 1024 * 1024, maxBatchSize: 256, }; } exports.getProviderSpecificFeatures = getProviderSpecificFeatures;