"use strict"; var __webpack_require__ = {}; (()=>{ __webpack_require__.d = (exports1, definition)=>{ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, { enumerable: true, get: definition[key] }); }; })(); (()=>{ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop); })(); (()=>{ __webpack_require__.r = (exports1)=>{ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, { value: 'Module' }); Object.defineProperty(exports1, '__esModule', { value: true }); }; })(); var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { AhaStreamReciver: ()=>AhaStreamReciver, AhaStreamReceiver: ()=>AhaStreamReceiver, AhaStreamSender: ()=>AhaStreamSender, JSONRPC_ERRORS: ()=>JSONRPC_ERRORS, RPCError: ()=>RPCError, AhaStream: ()=>AhaStream, OrderedLazyStream: ()=>OrderedLazyStream, defaultLogger: ()=>defaultLogger, LogLevel: ()=>logger_LogLevel, Connection: ()=>Connection, Logger: ()=>Logger }); function toRequestMethod(method) { if ("string" == typeof method) return { method: method }; return { method: method.method, meta: method.meta }; } function isIError(obj) { return obj && "number" == typeof obj.code && "string" == typeof obj.message; } const JSONRPC_ERRORS = { PARSE_ERROR: { code: -32700 }, INVALID_REQUEST: { code: -32600 }, METHOD_NOT_FOUND: { code: -32601 }, INVALID_PARAMS: { code: -32602 }, INTERNAL_ERROR: { code: -32603 } }; const isNotUndefinedOrNull = (value)=>null != value; function undefinedToNull(param) { if (void 0 === param) return null; return param; } function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { const r = 16 * Math.random() | 0, v = 'x' === c ? r : 0x3 & r | 0x8; return v.toString(16); }); } function createPromiseResolvers() { let resolve; let reject; const promise = new Promise((res, rej)=>{ resolve = res; reject = rej; }); return [ promise, resolve, reject ]; } class Sequencer { current = Promise.resolve(null); queue(promiseTask) { return this.current = this.current.then(()=>promiseTask(), ()=>promiseTask()); } } class Disposable { disposed = false; _disposables = []; get isDisposed() { return this.disposed; } dispose() { if (this.disposed) return; this.disposed = true; this._disposables.forEach((d)=>d.dispose()); } _register(disposable) { this._disposables.push(disposable); return disposable; } add(disposable) { this._disposables.push(disposable); return { dispose: ()=>{ const index = this._disposables.indexOf(disposable); if (index >= 0) { disposable.dispose(); this._disposables.splice(index, 1); } } }; } } let createNanoEvents = ()=>({ emit (event, ...args) { for(let callbacks = this.events[event] || [], i = 0, length = callbacks.length; i < length; i++)callbacks[i](...args); }, events: {}, on (event, cb) { (this.events[event] ||= []).push(cb); return ()=>{ this.events[event] = this.events[event]?.filter((i)=>cb !== i); }; } }); class RPCError extends Error { code; data; constructor(code, message, data){ super(message), this.code = code, this.data = data; } toJSON() { return { code: this.code, message: this.message, data: this.data }; } static fromErrorObj(err) { return new RPCError(err.code, err.message, err.data); } static serialize(error, method) { if (error instanceof RPCError) return error.toJSON(); if (error instanceof Error) return { code: JSONRPC_ERRORS.INTERNAL_ERROR.code, message: method ? `Request ${method} failed with message: ${error.message}` : error.message, data: error.data ?? { stack: error.stack } }; if (isIError(error)) return { code: error.code, message: method ? `Request ${method} failed with message: ${error.message}` : error.message, data: error.data }; if (error && error.message) return { code: JSONRPC_ERRORS.INTERNAL_ERROR.code, message: method ? `Request ${method} failed with message: ${error.message}` : error.message, data: error.data }; return { code: JSONRPC_ERRORS.INTERNAL_ERROR.code, message: method ? `Request ${method} failed` : "Request failed" }; } } const STREAM_NOTIFICATION_PREFIX = 'rpc.stream.'; const STREAM_CANCEL_NOTIFICATION_PREFIX = 'rpc.stream.cancel.'; const dummyOff = ()=>{}; class OrderedLazyStream { emitter = createNanoEvents(); buffer = []; ended = false; dispatching = false; started = false; destroyed = false; finishedInfo = null; on(event, handler) { if (this.destroyed) { if ('finished' !== event) return dummyOff; } const off = this.emitter.on(event, handler); this.startIfNeeded(); if ('end' === event && this.ended) queueMicrotask(()=>{ try { handler(); } catch (e) { this.emit('error', e); } }); if ('finished' === event && this.finishedInfo) queueMicrotask(()=>{ try { handler(this.finishedInfo); } catch {} }); return off; } once(event, handler) { const wrapper = (...args)=>{ off?.(); handler(...args); }; const off = this.on(event, wrapper); return this; } emit(event, ...args) { if (this.destroyed) return; if ('data' === event) { const [chunk] = args; this.enqueueData(chunk); } else if ('end' === event) this.markEnd(); else if ('error' === event) { const [err] = args; this.emitError(err); } else this.emitter.emit(event, ...args); } async read() { if (this.destroyed) return null; this.startIfNeeded(); return new Promise((resolve, reject)=>{ const cleanup = ()=>{ offData(); offEnd(); offError(); }; const offData = this.on('data', (chunk)=>{ cleanup(); resolve(chunk); }); const offEnd = this.on('end', ()=>{ cleanup(); resolve(null); }); const offError = this.on('error', (err)=>{ cleanup(); reject(err); }); this.drain(); }); } trackFinished(callback) { this.once('finished', callback); } destroy(error) { if (this.destroyed) return; this.destroyed = true; if (void 0 !== error) this.emitError(error); else this.finish({ type: 'disposed' }); queueMicrotask(()=>this.clearAllListeners()); } dispose() { this.destroy(); } hasListeners(event) { const listeners = this.emitter.events[event]; return !!(listeners && listeners.length > 0); } startIfNeeded() { if (this.started || this.destroyed) return; const hasConsumer = this.hasListeners('data') || this.hasListeners('end'); if (!hasConsumer) return; this.started = true; this.drain(); } enqueueData(chunk) { if (this.ended) return void this.emitError(new Error('Cannot emit data after end')); this.buffer.push(chunk); if (this.started) this.drain(); } markEnd() { if (this.ended) return; this.ended = true; if (this.started) this.drain(); this.finish({ type: 'end' }); } drain() { if (this.dispatching) return; this.dispatching = true; try { while(this.buffer.length > 0 && this.hasListeners('data')){ const chunk = this.buffer.shift(); try { this.emitter.emit('data', chunk); } catch (e) { this.emit('error', e); } } if (this.ended && 0 === this.buffer.length && this.hasListeners('end')) queueMicrotask(()=>{ try { this.emitter.emit('end'); } catch (e) { this.emit('error', e); } }); } finally{ this.dispatching = false; } } emitError(err) { this.emitter.emit('error', err); if (!this.ended) { this.ended = true; this.drain(); } this.finish({ type: 'error', error: err }); } finish(info) { if (this.finishedInfo) return; this.finishedInfo = info; const emitFinished = ()=>{ try { this.emitter.emit('finished', info); } catch {} }; queueMicrotask(emitFinished); } clearAllListeners() { this.emitter.events = {}; } } class AhaStream extends Disposable { connection; stream; logger; constructor(connection){ super(), this.connection = connection; this.stream = this._register(new OrderedLazyStream()); this.logger = connection.logger; } emit(event, ...args) { if (this.isDisposed) return void this.logger.warn('Attempted to emit event on disposed stream:', event); this.logger.trace('Stream emit event:', event); this.stream.emit(event, ...args); } on(event, callback) { if (this.isDisposed) { this.logger.warn('Attempted to register event listener on disposed stream:', event); return { dispose: ()=>{} }; } const off = this.stream.on(event, callback); return { dispose: ()=>off() }; } trackFinished(callback) { const wrapper = ()=>{ callback(); this.stream.clearAllListeners(); }; this.stream.once('finished', wrapper); } } class AhaStreamSender extends AhaStream { streamId; chunkIndex = 0; isEnded = false; sequencer = new Sequencer(); constructor(connection, streamId){ super(connection); this.streamId = streamId || uuid(); this.setupReceiver(); } setupReceiver() { const cancelNotification = `${STREAM_CANCEL_NOTIFICATION_PREFIX}${this.streamId}`; this._register(this.connection.onNotificationRaw(cancelNotification, ()=>{ this.logger.info("Cancelled"); this.cancel(); this.end(); this.dispose(); })); } async write(chunk) { if (this.isDisposed) throw new Error('Stream already disposed'); if (this.isEnded) throw new Error('Stream already ended'); return this.sequencer.queue(async ()=>{ await this.connection.sendNotification({ method: `${STREAM_NOTIFICATION_PREFIX}${this.streamId}`, meta: { stream: true, streamId: this.streamId, chunkIndex: this.chunkIndex++ } }, { data: chunk }); }); } async end(chunk) { if (this.isDisposed) throw new Error('Stream already disposed'); if (this.isEnded) return; if (void 0 !== chunk) this.write(chunk); return this.sequencer.queue(async ()=>{ await this.connection.sendNotification({ method: `${STREAM_NOTIFICATION_PREFIX}${this.streamId}`, meta: { stream: true, streamId: this.streamId, chunkIndex: this.chunkIndex, done: true } }, { data: null }); this.isEnded = true; }); } on(event, callback) { return super.on(event, callback); } async error(err) { if (this.isDisposed) throw new Error('Stream already disposed'); if (this.isEnded) return; const errorObj = RPCError.serialize(err); return this.sequencer.queue(async ()=>{ await this.connection.sendNotification({ method: `${STREAM_NOTIFICATION_PREFIX}${this.streamId}`, meta: { stream: true, streamId: this.streamId, chunkIndex: this.chunkIndex, done: true } }, { error: errorObj }); this.isEnded = true; }); } cancel() { this.emit('cancel'); } onCancel(callback) { return this.on('cancel', callback); } } class AhaStreamReceiver extends AhaStream { streamId; timeoutTimer; lastChunkTime = Date.now(); timeout; constructor(connection, streamId, options){ super(connection), this.streamId = streamId; this.timeout = options?.timeout ?? -1; this.setupReceiveHandler(); this.startTimeoutCheck(); } close(reason) { this.connection.cancelStreamRequest(this.streamId, reason); } async collect() { const [promise, resolve, reject] = createPromiseResolvers(); if (this.isDisposed) { reject(new Error('Stream already disposed')); return []; } const chunks = []; this.on('data', (chunk)=>{ this.logger.trace('Stream received chunk:', chunk); chunks.push(chunk); }); this.on('end', ()=>{ this.logger.debug('Stream completed, total chunks:', chunks.length); this.dispose(); resolve(chunks); }); this.on('error', (err)=>{ this.dispose(); reject(err); }); return promise; } startTimeoutCheck() { if (this.timeout <= 0) return; this.timeoutTimer = setInterval(()=>{ if (this.isDisposed) return void this.stopTimeoutCheck(); const elapsed = Date.now() - this.lastChunkTime; if (elapsed > this.timeout) { const error = new RPCError(-32000, `Stream timeout after ${this.timeout}ms`, { streamId: this.streamId }); this.emit('error', error); this.dispose(); } }, 1000); } stopTimeoutCheck() { if (this.timeoutTimer) { clearInterval(this.timeoutTimer); this.timeoutTimer = void 0; } } setupReceiveHandler() { const notificationMethod = `${STREAM_NOTIFICATION_PREFIX}${this.streamId}`; const handler = ({ meta }, params)=>{ this.logger.trace('Stream notification received:', { method: notificationMethod, params, meta }); if (this.isDisposed) return; if (!meta?.stream || meta.streamId !== this.streamId) return; this.lastChunkTime = Date.now(); if (params.error) { const error = RPCError.fromErrorObj(params.error); this.emit('error', error); this.stopTimeoutCheck(); return; } if (meta.done) { this.logger.trace('Stream done'); this.emit('end'); this.stopTimeoutCheck(); return; } if (void 0 !== params.data) this.emit('data', params.data); }; this._register(this.connection.onNotificationRaw(notificationMethod, handler)); } dispose() { if (this.isDisposed) return; this.stopTimeoutCheck(); this.stream.dispose(); super.dispose(); } } const AhaStreamReciver = AhaStreamReceiver; var logger_LogLevel = /*#__PURE__*/ function(LogLevel) { LogLevel[LogLevel["NONE"] = 0] = "NONE"; LogLevel[LogLevel["ERROR"] = 1] = "ERROR"; LogLevel[LogLevel["WARN"] = 2] = "WARN"; LogLevel[LogLevel["INFO"] = 3] = "INFO"; LogLevel[LogLevel["DEBUG"] = 4] = "DEBUG"; LogLevel[LogLevel["TRACE"] = 5] = "TRACE"; return LogLevel; }({}); class Logger { level; prefix; constructor(level = 2, prefix = "[AHA-RPC]"){ this.level = level; this.prefix = prefix; } setLevel(level) { this.level = level; } formatMessage(levelName, message) { const timestamp = new Date().toISOString(); return `[${timestamp}] ${this.prefix} [${levelName}] ${message}`; } error(message, ...args) { if (this.level >= 1) console.error(this.formatMessage("ERROR", message), ...args); } warn(message, ...args) { if (this.level >= 2) console.warn(this.formatMessage("WARN", message), ...args); } info(message, ...args) { if (this.level >= 3) console.info(this.formatMessage("INFO", message), ...args); } debug(message, ...args) { if (this.level >= 4) console.log(this.formatMessage("DEBUG", message), ...args); } trace(message, ...args) { if (this.level >= 5) console.log(this.formatMessage("TRACE", message), ...args); } } const defaultLogger = new Logger(2); class JSONRPCSerializer { serializeMessage(method, params, meta, id) { const payload = { jsonrpc: '2.0', method }; if (void 0 !== id) payload.id = id; if (void 0 !== meta) payload.meta = meta; if (void 0 !== params) if (Array.isArray(params) || 'object' == typeof params) payload.params = params; else throw new Error('params must be an array or object'); return JSON.stringify(payload); } serializeRequest(request) { return this.serializeMessage(request.method, request.params, request.meta, request.id); } serializeNotification(notification) { return this.serializeMessage(notification.method, notification.params, notification.meta); } serializeResponse(response) { return JSON.stringify({ jsonrpc: '2.0', id: response.id, meta: response.meta, result: response.result, error: response.error }); } deserialize(response) { try { const data = JSON.parse(response); return data; } catch (e) { throw new RPCError(JSONRPC_ERRORS.PARSE_ERROR.code, `Parse error: ${e?.message ?? 'Unknown parse error'}`, { raw: response }); } } } class Connection extends Disposable { channel; _requestId = 0; serializer; _requestPromises = new Map(); _requestCallbacks = new Map(); _errorCallback; _activeStreams = new Set(); logger; constructor(channel, options){ super(), this.channel = channel; this.serializer = new JSONRPCSerializer(); this.logger = options?.logger ?? defaultLogger; this._errorCallback = (error, raw)=>{ this.logger.error('Connection error:', error, raw); }; this._register(this.channel.onData((data)=>{ try { const v = this.serializer.deserialize(data); if (Array.isArray(v)) v.forEach((item)=>this.resolveAnyMessage(item)); else this.resolveAnyMessage(v); } catch (error) { try { this._errorCallback?.(error, data); } catch {} } })); } onError(callback) { const previous = this._errorCallback; this._errorCallback = callback; return { dispose: ()=>{ this._errorCallback = previous; } }; } resolveAnyMessage(v) { const isRequest = isNotUndefinedOrNull(v.method); if (isRequest) this.resolveRequest(v); else this.resolveResponse(v); } resolveResponse(resp) { const callback = this._requestPromises.get(resp.id); this._requestPromises.delete(resp.id); if (callback) if (resp.error) { const err = RPCError.fromErrorObj(resp.error); callback.reject(err); } else callback.resolve(resp.result); } async reply(result, err, req) { const shouldReply = isNotUndefinedOrNull(req.id); if (!shouldReply) return; const response = { id: req.id }; if (err) response.error = err; else response.result = void 0 === result ? null : result; const responseString = this.serializer.serializeResponse(response); await this.channel.send(responseString); } async resolveRequest(req) { const callback = this._requestCallbacks.get(req.method) || this._requestCallbacks.get('*'); if (callback) try { let result; if (callback.isRaw) { const { params, ...rest } = req; this.logger.debug('Received request:', req); result = Array.isArray(params) ? await callback.callback(rest, ...params) : await callback.callback(rest, params); } else result = Array.isArray(req.params) ? await callback.callback(...req.params) : await callback.callback(req.params); await this.reply(result, void 0, req); } catch (error) { return await this.reply(void 0, RPCError.serialize(error, req.method), req); } else await this.reply(void 0, { code: JSONRPC_ERRORS.METHOD_NOT_FOUND.code, message: `Method ${req.method} not found` }, req); } normalizeParams(params) { switch(params.length){ case 0: return; case 1: return [ undefinedToNull(params[0]) ]; default: { const result = []; for(let i = 0; i < params.length; i++)result.push(undefinedToNull(params[i])); return result; } } } async sendNotification(method, ...params) { const { method: methodName, meta } = toRequestMethod(method); const notification = { method: methodName, params: this.normalizeParams(params), meta }; await this.channel.send(this.serializer.serializeNotification(notification)); } async sendRequest(method, ...params) { const [promise, resolve, reject] = createPromiseResolvers(); const requestId = String(this._requestId++); const { method: methodName, meta } = toRequestMethod(method); const request = { method: methodName, params: this.normalizeParams(params), id: requestId, meta }; this._requestPromises.set(requestId, { method: methodName, resolve, reject }); await this.channel.send(this.serializer.serializeRequest(request)); return promise; } async sendStreamRequest(method, ...params) { const response = await this.sendRequest(method, ...params); const streamId = response.streamId; if (!streamId) throw new Error('Stream ID not found in response'); const stream = new AhaStreamReceiver(this, streamId); this._trackStream(stream); return stream; } async cancelStreamRequest(streamId, reason) { await this.sendNotification(`${STREAM_CANCEL_NOTIFICATION_PREFIX}${streamId}`, { streamId, reason }); } createStreamSender(streamId) { const stream = new AhaStreamSender(this, streamId); this._trackStream(stream); return stream; } createStreamReceiver(streamId) { const stream = new AhaStreamReceiver(this, streamId ?? uuid()); this._trackStream(stream); return stream; } _trackStream(stream) { this._activeStreams.add(stream); const cleanup = ()=>{ this._activeStreams.delete(stream); }; stream.trackFinished(cleanup); } onNotification(method, callback) { this._requestCallbacks.set(method, { callback }); return { dispose: ()=>{ this._requestCallbacks.delete(method); } }; } onNotificationRaw(method, callback) { this._requestCallbacks.set(method, { callback, isRaw: true }); return { dispose: ()=>{ this._requestCallbacks.delete(method); } }; } onRequest(method, callback) { this._requestCallbacks.set(method, { callback }); return { dispose: ()=>{ this._requestCallbacks.delete(method); } }; } onStreamRequest(method, callback) { return this.onRequestRaw(method, async (req, ...args)=>{ const stream = await callback(req, ...args); return { streamId: stream.streamId }; }); } onRequestRaw(method, callback) { this._requestCallbacks.set(method, { callback, isRaw: true }); return { dispose: ()=>{ this._requestCallbacks.delete(method); } }; } dispose() { this._activeStreams.forEach((stream)=>{ stream.dispose(); }); this._activeStreams.clear(); super.dispose(); } } exports.AhaStream = __webpack_exports__.AhaStream; exports.AhaStreamReceiver = __webpack_exports__.AhaStreamReceiver; exports.AhaStreamReciver = __webpack_exports__.AhaStreamReciver; exports.AhaStreamSender = __webpack_exports__.AhaStreamSender; exports.Connection = __webpack_exports__.Connection; exports.JSONRPC_ERRORS = __webpack_exports__.JSONRPC_ERRORS; exports.LogLevel = __webpack_exports__.LogLevel; exports.Logger = __webpack_exports__.Logger; exports.OrderedLazyStream = __webpack_exports__.OrderedLazyStream; exports.RPCError = __webpack_exports__.RPCError; exports.defaultLogger = __webpack_exports__.defaultLogger; for(var __webpack_i__ in __webpack_exports__)if (-1 === [ "AhaStream", "AhaStreamReceiver", "AhaStreamReciver", "AhaStreamSender", "Connection", "JSONRPC_ERRORS", "LogLevel", "Logger", "OrderedLazyStream", "RPCError", "defaultLogger" ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__]; Object.defineProperty(exports, '__esModule', { value: true });