// NatsUtils.js (Stateless Utility - Minimal Imports Version) // Import only the essentials needed for basic pub/sub/req/status // We assume these are all exported by your "../esm/nats.js" bundle import { connect, // For establishing the connection JSONCodec, // For encoding/decoding JSON payloads StringCodec, // For decoding potential error payloads or raw strings // Subscription object type might be implicitly handled or imported if needed for type hinting // Methods like publish, subscribe, request, status, close are part of the 'nc' object returned by connect. } from "../nats.ws-1.30.3/esm/nats.js"; // <--- Adjust this path as needed class NatsUtils { /** * Get NATS Codecs. * @returns {{jsonCodec: object, stringCodec: object}} */ static getCodecs() { // We need to instantiate them. The imports just bring in the classes/factories. try { return { jsonCodec: JSONCodec(), stringCodec: StringCodec() }; } catch (e) { console.error("Failed to create NATS codecs. Ensure nats.ws is loaded correctly.", e); // Return dummy objects or null to avoid breaking caller immediately, // but subsequent operations will likely fail. return { jsonCodec: null, stringCodec: null }; } } /** * Connect to NATS server. * @param {string} url - WebSocket URL * @param {object} [options] - NATS connection options * @returns {Promise} - The connection instance (nc) */ static async Natsconnect(url, options = {}) { console.log(`Attempting NATS connection to ${url}...`); try { // 'connect' is imported directly const nc = await connect({ servers: url, ...options }); console.log("NATS connected."); nc.publish("enter", JSONCodec().encode({ id:"gwx" })); // Example publish nc.publish("enter", JSONCodec().encode({ id:"gwx2" })); // Example publish console.log("Published 'enter' message.",nc); return nc; } catch (err) { console.error("NATS connection failed:", err); throw err; // Re-throw for the caller to handle } } /** * Disconnect from NATS. * @param {NatsConnection} nc - The connection instance * @returns {Promise} */ static async disconnect(nc) { if (nc && !nc.isClosed()) { console.log("Closing NATS connection..."); try { await nc.close(); // Use the close method on the connection object console.log("NATS connection closed."); } catch (err) { console.error("Error closing NATS connection:", err); } } } /** * Check if connected. * @param {NatsConnection} nc - The connection instance * @returns {boolean} */ static isConnected(nc) { // Use the isClosed method on the connection object return nc && !nc.isClosed(); } /** * Publish a JSON message. * @param {NatsConnection} nc * @param {object} jsonCodec - Instance from getCodecs() * @param {string} subject * @param {object} data - JSON object * @returns {boolean} - Success indicator */ static publish(nc, jsonCodec, subject, data) { if (!this.isConnected(nc)) return false; if (!jsonCodec) { console.error("JSON Codec required for publish"); return false; } try { // Use the publish method on the connection object nc.publish(subject, jsonCodec.encode(data)); console.log(`Published to ${subject}:`, data); return true; } catch (err) { console.error(`Publish to ${subject} failed:`, err); return false; } } /** * Subscribe to a subject for JSON messages. * @param {NatsConnection} nc * @param {object} jsonCodec - Instance from getCodecs() * @param {string} subject * @param {function(object, string): void} callback - Receives (decodedData, messageSubject) * @returns {NatsSubscription | null} - The subscription object (for unsubscribing) */ static subscribe(nc, jsonCodec, subject, callback) { if (!this.isConnected(nc)) return null; if (!jsonCodec) { console.error("JSON Codec required for subscribe"); return null; } try { // Use the subscribe method on the connection object const sub = nc.subscribe(subject, { callback: (err, msg) => { if (err) { /* ... error handling ... */ return; } try { callback(jsonCodec.decode(msg.data), msg.subject); } catch (decodeErr) { /* ... decode error handling ... */ } }, }); console.log(`Subscription created for ${subject}`); return sub; } catch (err) { console.error(`Subscribe to ${subject} failed:`, err); return null; } } /** * Unsubscribe. * @param {NatsSubscription} subscription - The object returned by subscribe */ static unsubscribe(subscription) { if (subscription && typeof subscription.unsubscribe === 'function') { try { const subSubject = subscription.getSubject ? subscription.getSubject() : 'unknown'; // Get subject if method exists subscription.unsubscribe(); console.log(`Unsubscribed from ${subSubject}`); } catch (err) { console.error(`Unsubscribe failed:`, err); } } } /** * Send a JSON request and wait for a JSON reply. * @param {NatsConnection} nc * @param {object} jsonCodec - Instance from getCodecs() * @param {string} subject * @param {object} data - JSON request object * @param {number} [timeoutMs=10000] - Timeout * @returns {Promise} - Promise resolving with the JSON response object */ static async request(nc, jsonCodec, subject, data, timeoutMs = 10000) { if (!this.isConnected(nc)) throw new Error("NATS not connected"); if (!jsonCodec) throw new Error("JSON Codec required for request"); try { // Use the request method on the connection object const responseMsg = await nc.request(subject, jsonCodec.encode(data), { timeout: timeoutMs }); return jsonCodec.decode(responseMsg.data); } catch (err) { console.error(`Request to ${subject} failed:`, err.message); throw err; } } /** * Monitor connection status events. * @param {NatsConnection} nc * @param {function(string, any?): void} statusCallback - Receives (statusType, eventData) */ static monitorStatus(nc, statusCallback) { if (!nc) return; (async () => { try { console.log("Starting NATS status monitoring..."); statusCallback('monitoring_started'); // Use the status async iterator on the connection object for await (const s of nc.status()) { statusCallback(s.type, s.data); } console.log("NATS status monitoring finished (connection closed)."); statusCallback('closed'); } catch (err) { console.error("NATS status monitoring error:", err); statusCallback('monitoring_error', err); } })(); } } // Make it globally available or export window.NatsUtils = NatsUtils; // export default NatsUtils;