var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// node_modules/.pnpm/hash-sum@2.0.0/node_modules/hash-sum/hash-sum.js
var require_hash_sum = __commonJS({
  "node_modules/.pnpm/hash-sum@2.0.0/node_modules/hash-sum/hash-sum.js"(exports, module) {
    "use strict";
    function pad(hash, len) {
      while (hash.length < len) {
        hash = "0" + hash;
      }
      return hash;
    }
    function fold(hash, text) {
      var i;
      var chr;
      var len;
      if (text.length === 0) {
        return hash;
      }
      for (i = 0, len = text.length; i < len; i++) {
        chr = text.charCodeAt(i);
        hash = (hash << 5) - hash + chr;
        hash |= 0;
      }
      return hash < 0 ? hash * -2 : hash;
    }
    function foldObject(hash, o, seen) {
      return Object.keys(o).sort().reduce(foldKey, hash);
      function foldKey(hash2, key) {
        return foldValue(hash2, o[key], key, seen);
      }
    }
    function foldValue(input, value, key, seen) {
      var hash = fold(fold(fold(input, key), toString2(value)), typeof value);
      if (value === null) {
        return fold(hash, "null");
      }
      if (value === void 0) {
        return fold(hash, "undefined");
      }
      if (typeof value === "object" || typeof value === "function") {
        if (seen.indexOf(value) !== -1) {
          return fold(hash, "[Circular]" + key);
        }
        seen.push(value);
        var objHash = foldObject(hash, value, seen);
        if (!("valueOf" in value) || typeof value.valueOf !== "function") {
          return objHash;
        }
        try {
          return fold(objHash, String(value.valueOf()));
        } catch (err) {
          return fold(objHash, "[valueOf exception]" + (err.stack || err.message));
        }
      }
      return fold(hash, value.toString());
    }
    function toString2(o) {
      return Object.prototype.toString.call(o);
    }
    function sum(o) {
      return pad(foldValue(0, o, "", []).toString(16), 8);
    }
    module.exports = sum;
  }
});

// src/RPC.ts
var import_hash_sum = __toESM(require_hash_sum(), 1);
var customAlphabet = (alphabet) => {
  return (size) => {
    let id = "";
    let i = size;
    while (i--) {
      id += alphabet[Math.random() * alphabet.length | 0];
    }
    return id;
  };
};
var nanoid = customAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz");
var RPCError = class extends Error {
  constructor(message, code) {
    super(message);
    this._code = code || 0;
    this._message = message;
  }
  get message() {
    return this._message;
  }
  get code() {
    return this._code;
  }
  toString() {
    return `${this._code} ${this._message}`;
  }
  toResponse(id) {
    return {
      jsonrpc: "2.0",
      id,
      error: {
        code: this._code,
        message: this._message
      }
    };
  }
};
var RPCResult = class {
  constructor(result) {
    this._result = result;
  }
  get result() {
    return this._result;
  }
  toResponse(id) {
    return {
      jsonrpc: "2.0",
      id,
      result: this._result
    };
  }
};
var rpcTimeout = {};
var rpcTimeoutGC;
function setRPCTimeout(callback, timeout) {
  const timeoutId = nanoid(8);
  rpcTimeout[timeoutId] = {
    expires: Date.now() + timeout,
    callback
  };
  if (!rpcTimeoutGC) {
    rpcTimeoutGC = setInterval(() => {
      const now = Date.now();
      Object.keys(rpcTimeout).forEach((timeoutId2) => {
        const { expires, callback: callback2 } = rpcTimeout[timeoutId2];
        if (now >= expires) {
          delete rpcTimeout[timeoutId2];
          callback2();
        }
      });
    }, 500);
  }
  return timeoutId;
}
function clearRPCTimeout(timeoutId) {
  delete rpcTimeout[timeoutId];
  if (Object.keys(rpcTimeout).length == 0) {
    clearInterval(rpcTimeoutGC);
    rpcTimeoutGC = void 0;
  }
}
var _RPC = class {
  constructor(send, options) {
    this._promises = {};
    this._callingHandlers = {};
    this._patterns = [];
    this._hashedFunctions = {};
    this._hashedRemoteFunctions = {};
    this._remoteObjects = {};
    this._remoteObjectClusters = {};
    this._proxiedRemoteObjects = {};
    this._extendedRPCs = [];
    this._readyCallbacks = [];
    this._notReadyCallbacks = [];
    this._send = send;
    this._options = { timeout: 5e3, ready: true, ...options };
    this.on("_.Function.call", (hash, params) => {
      if (this._hashedFunctions.hasOwnProperty(hash)) {
        let f = this._hashedFunctions[hash];
        return Promise.resolve(f(...params));
      }
      return Promise.resolve();
    });
    this.on("_.Function.release", (hash) => {
      if (this._hashedFunctions.hasOwnProperty(hash)) {
        delete this._hashedFunctions[hash];
      }
    });
    this.on("_.Object.set", (objectId, path, value) => {
      var _a;
      try {
        const obj = this._remoteObjects[objectId];
        const props = path.split(".");
        const lastProp = props.pop();
        let o = obj;
        for (let p of props) {
          o = Reflect.get(o, p);
        }
        Reflect.set(o, lastProp, value);
      } catch (e) {
        (_a = this._options.logger) == null ? void 0 : _a.debug(e);
      }
    });
    this.on("_.Object.get", (objectId) => {
      const obj = this._remoteObjects[objectId];
      return Promise.resolve(obj).then((o) => {
        return JSON.parse(JSON.stringify(o));
      }).catch((e) => {
        var _a;
        (_a = this._options.logger) == null ? void 0 : _a.debug("_.Object.get error", e);
      });
    });
    this.on("_.Object.apply", (remoteId, path, params) => {
      const obj = this._remoteObjects[remoteId];
      let passToRemote, props;
      if (path.endsWith("$")) {
        props = path.slice(0, -1).split(".");
        passToRemote = true;
      } else {
        props = path.split(".");
        passToRemote = false;
      }
      const lastProp = props.pop();
      let o = obj;
      for (let p of props) {
        o = Reflect.get(o, p);
      }
      return Promise.resolve(Reflect.apply(o[lastProp], o, params)).then((ret) => {
        if (passToRemote) {
          return JSON.parse(JSON.stringify(ret));
        }
        return this._makeRemoteObject(ret, remoteId);
      });
    });
    this.on("_.Object.release", (remoteId) => {
      const cluster = this._remoteObjectClusters[remoteId] || [];
      cluster.map((key) => delete this._remoteObjects[key]);
      delete this._remoteObjectClusters[remoteId];
      return true;
    });
    this.setReady(this._options.ready);
  }
  stat() {
    const objects = {};
    Object.keys(this._remoteObjectClusters).forEach((remoteId) => {
      objects[remoteId] = {};
      (this._remoteObjectClusters[remoteId] || []).forEach((key) => {
        objects[remoteId][key] = this._remoteObjects[key];
      });
    });
    return {
      functions: this._hashedFunctions,
      objects
    };
  }
  setTimeout(timeout) {
    this._options.timeout = timeout;
  }
  _decodeNonScalars(params) {
    const self = this;
    const _decode = (param) => {
      if (param === Object(param)) {
        if (param["@func"] === "1.0" && Reflect.has(param, "hash")) {
          let hash = param.hash;
          if (!this._hashedRemoteFunctions[hash]) {
            this._hashedRemoteFunctions[hash] = new Proxy(() => {
            }, {
              get(target, prop) {
                const sProp = String(prop);
                if (Reflect.has(target, prop)) {
                  return target[prop];
                }
                if (sProp === "release") {
                  target.release = () => {
                    delete this._hashedRemoteFunctions[hash];
                    self.notify("_.Function.release", [hash]);
                    target.release = () => {
                    };
                    target.release.BEEN_CALLED = true;
                  };
                  return target.release;
                }
              },
              apply(target, __, params2) {
                if (!target.release || target.release.BEEN_CALLED === void 0) {
                  return self.call("_.Function.call", [hash, params2]);
                }
              }
            });
          }
          return this._hashedFunctions[hash];
        } else {
          for (let k in param) {
            param[k] = _decode(param[k]);
          }
        }
      } else if (Array.isArray(param)) {
        return param.map((p) => _decode(p));
      } else if (_RPC.bufferDecode && typeof param === "string" && param.slice(0, 5) === "@buf:") {
        return _RPC.bufferDecode(param.slice(5));
      }
      return param;
    };
    return _decode(params);
  }
  _encodeNonScalars(params) {
    const _encode = (param) => {
      if (typeof param === "function") {
        let hash = (0, import_hash_sum.default)(param);
        this._hashedFunctions[hash] = param;
        return { "@func": "1.0", hash };
      } else if (_RPC.isBuffer && _RPC.bufferEncode && _RPC.isBuffer(param)) {
        return "@buf:" + _RPC.bufferEncode(param);
      } else if (Array.isArray(param)) {
        return param.map((p) => _encode(p));
      } else if (Object(param) === param) {
        for (let k in param) {
          param[k] = _encode(param[k]);
        }
      }
      return param;
    };
    return _encode(params);
  }
  _makeRemoteObject(obj, clusterId) {
    const id = nanoid(16);
    this._remoteObjects[id] = obj;
    clusterId = clusterId || id;
    const cluster = this._remoteObjectClusters[clusterId] || [];
    cluster.push(id);
    this._remoteObjectClusters[clusterId] = cluster;
    return { $: true, id };
  }
  extends(rpc) {
    if (!this._extendedRPCs.some((it) => it === rpc)) {
      this._extendedRPCs.push(rpc);
    }
  }
  _getHandler(method) {
    const key = method.toLowerCase();
    if (this._callingHandlers.hasOwnProperty(key)) {
      const handler = this._callingHandlers[key];
      if (handler.once) {
        delete this._callingHandlers[key];
      }
      return [handler.callback];
    }
    for (let p of this._patterns) {
      const matches = method.match(p.pattern);
      if (matches) {
        return [p.callback, matches];
      }
    }
    return [void 0];
  }
  receive(request) {
    var _a, _b, _c;
    if (typeof request === "string") {
      try {
        request = JSON.parse(request);
      } catch (e) {
        this._sendError(new RPCError("Parse error", -32700));
        return;
      }
    }
    if (request.jsonrpc !== "2.0") {
      this._sendError(new RPCError("Parse error", -32700));
      return;
    }
    if (Reflect.has(request, "method")) {
      let method = request.method;
      let params = request.params;
      let remote;
      if (method.slice(-1) === "$") {
        method = method.slice(0, -1);
        remote = true;
      } else {
        remote = false;
      }
      (_a = this._options.logger) == null ? void 0 : _a.debug(`${request.id ? "called" : "notified"} via ${method}`, { params });
      let [f, matches] = this._getHandler(method);
      if (f === void 0 && this._extendedRPCs.length > 0) {
        for (let rpc of this._extendedRPCs) {
          [f, matches] = rpc._getHandler(method);
          if (f)
            break;
        }
      }
      if (f === void 0) {
        if (request.id) {
          this._sendError(new RPCError(`Method "${method}" not found`, -32601), request.id);
        }
        return;
      }
      params = this._decodeNonScalars(params);
      if (!Array.isArray(params)) {
        params = [params];
      }
      if (matches) {
        params = [params, matches];
      }
      const _sendError = (e) => {
        if (e instanceof RPCError) {
          this._sendError(e, request.id);
        } else {
          this._sendError(new RPCError(String(e), -32603), request.id);
        }
      };
      try {
        Promise.resolve(f.bind(this)(...params)).then((result) => {
          if (remote) {
            result = this._makeRemoteObject(result);
          } else {
            result = this._encodeNonScalars(result);
          }
          if (request.id) {
            this._sendResult(result, request.id);
          }
        }).catch(_sendError);
      } catch (e) {
        _sendError(e);
      }
    } else if (Reflect.has(request, "error")) {
      if (request.id && this._promises.hasOwnProperty(request.id)) {
        let promise = this._promises[request.id];
        (_b = this._options.logger) == null ? void 0 : _b.debug(`call ${promise.method} -> error ${request.error.code}`, {
          params: promise.params,
          error: request.error
        });
        promise.reject(request.error);
        promise.timeout && clearRPCTimeout(promise.timeout);
        delete this._promises[request.id];
      }
    } else if (Reflect.has(request, "result")) {
      if (request.id && this._promises.hasOwnProperty(request.id)) {
        let promise = this._promises[request.id];
        let result = request.result;
        (_c = this._options.logger) == null ? void 0 : _c.debug(`call ${promise.method} -> success`, {
          params: promise.params,
          result: request.result
        });
        if (result && typeof result === "object" && result.$ && result.id) {
          const self = this;
          const objectId = result.id;
          const ObjectHandler = {
            set(target, prop, value) {
              const sProp = String(prop);
              const propName = target.$$baseName ? `${target.$$baseName}.${sProp}` : sProp;
              self.call("_.Object.set", [objectId, propName, value]);
              return true;
            },
            get(target, prop) {
              const sProp = String(prop);
              if (sProp === "then" || sProp.substring(0, 2) === "$$") {
                return void 0;
              }
              if (Reflect.has(target, prop)) {
                return target[prop];
              }
              if (!Reflect.has(target.$$cache, prop)) {
                target.$$cache[prop] = new Proxy(
                  Object.assign(() => {
                  }, {
                    $$baseName: target.$$baseName ? `${target.$$baseName}.${sProp}` : sProp,
                    $$cache: {}
                  }),
                  ObjectHandler
                );
              }
              return target.$$cache[prop];
            },
            apply(target, _, params) {
              return self._proxiedRemoteObjects[objectId] && self.call("_.Object.apply", [objectId, target.$$baseName, params]);
            }
          };
          self._proxiedRemoteObjects[objectId] = true;
          const $$cache = {};
          result = new Proxy(
            Object.assign(() => {
            }, {
              $$cache,
              release$() {
                Object.keys($$cache).forEach((prop) => delete $$cache[prop]);
                return self.call("_.Object.release", [objectId]).finally(() => {
                  delete self._proxiedRemoteObjects[objectId];
                });
              },
              get$() {
                return self.call("_.Object.get", [objectId]);
              }
            }),
            ObjectHandler
          );
        } else {
          result = this._decodeNonScalars(result);
        }
        promise.resolve(result);
        promise.timeout && clearRPCTimeout(promise.timeout);
        delete this._promises[request.id];
      }
    }
  }
  async _sendResult(result, id) {
    const data = {
      jsonrpc: "2.0",
      id,
      result: result === void 0 ? null : result
    };
    try {
      await Promise.resolve(this._send(data));
    } catch (e) {
    }
  }
  async _sendError(e, id) {
    const data = {
      jsonrpc: "2.0",
      id,
      error: {
        code: e.code,
        message: e.message
      }
    };
    try {
      await Promise.resolve(this._send(data));
    } catch (e2) {
    }
  }
  async _sendRequest(method, params, id) {
    const data = {
      jsonrpc: "2.0",
      id,
      method,
      params
    };
    try {
      await Promise.resolve(this._send(data));
    } catch (e) {
    }
  }
  setReady(ready = true) {
    var _a, _b, _c, _d;
    if (ready) {
      if (this._readyPromise && !this._readyPromise.resolved) {
        this._readyPromise.resolved = true;
        (_b = (_a = this._readyPromise).resolve) == null ? void 0 : _b.call(_a);
        this._readyPromise = void 0;
      }
      if (!this._readyCallbacks.called) {
        this._readyCallbacks.called = true;
        this._readyCallbacks.forEach((it) => it());
      }
      if (!this._notReadyPromise || this._notReadyPromise.resolved) {
        this._notReadyPromise = {
          promise: new Promise(
            (resolve) => setTimeout(() => {
              if (!this._notReadyPromise)
                return;
              this._notReadyPromise.resolve = resolve;
              if (this._notReadyPromise.resolved) {
                resolve();
              }
            })
          ),
          resolved: false
        };
      }
      delete this._notReadyCallbacks.called;
    } else {
      if (this._notReadyPromise && !this._notReadyPromise.resolved) {
        this._notReadyPromise.resolved = true;
        (_d = (_c = this._notReadyPromise).resolve) == null ? void 0 : _d.call(_c);
        this._notReadyPromise = void 0;
      }
      if (!this._notReadyCallbacks.called) {
        this._notReadyCallbacks.called = true;
        this._notReadyCallbacks.forEach((it) => it());
      }
      if (!this._readyPromise || this._readyPromise.resolved) {
        this._readyPromise = {
          promise: new Promise(
            (resolve) => setTimeout(() => {
              if (!this._readyPromise)
                return;
              this._readyPromise.resolve = resolve;
              if (this._readyPromise.resolved) {
                resolve();
              }
            })
          ),
          resolved: false
        };
      }
      delete this._readyCallbacks.called;
    }
  }
  setOptions(options) {
    this._options = { ...this._options, ...options };
  }
  whenReady(callback) {
    if (!callback)
      return;
    this._readyCallbacks.push(callback);
    if (this._readyCallbacks.called) {
      setTimeout(() => callback());
    }
  }
  whenNotReady(callback) {
    if (!callback)
      return;
    this._notReadyCallbacks.push(callback);
    if (this._notReadyCallbacks.called) {
      setTimeout(() => callback());
    }
  }
  notify(method, params = {}) {
    const promise = this._readyPromise && !this._readyPromise.resolved ? this._readyPromise.promise : Promise.resolve();
    promise.then(() => {
      var _a;
      (_a = this._options.logger) == null ? void 0 : _a.debug(`notify ${method}`, { method, params });
      this._sendRequest(method, this._encodeNonScalars(params));
    });
  }
  call(method, params = {}, timeout) {
    const promise = this._readyPromise && !this._readyPromise.resolved ? this._readyPromise.promise : Promise.resolve();
    return promise.then(
      () => new Promise((resolve, reject) => {
        let id = nanoid(8);
        this._sendRequest(method, this._encodeNonScalars(params), id);
        timeout = timeout || this._options.timeout;
        let timeoutId;
        if (timeout !== -1) {
          timeoutId = setRPCTimeout(() => {
            delete this._promises[id];
            reject(new RPCError("Call timeout", -32603));
          }, timeout);
        }
        this._promises[id] = {
          method,
          params,
          resolve,
          reject,
          timeout: timeoutId
        };
      })
    );
  }
  once(method, callback) {
    return this.on(method, callback, true);
  }
  on(method, callback, once = false) {
    if (typeof method !== "string") {
      this._patterns.push({
        pattern: method,
        callback
      });
    } else {
      this._callingHandlers[method.toLowerCase()] = { callback, once };
    }
    return this;
  }
  off(method) {
    if (typeof method !== "string") {
      for (let key in this._callingHandlers) {
        if (key.match(method) != null)
          delete this._callingHandlers[key];
      }
      let str = method.toString();
      this._patterns = this._patterns.filter((p) => p.pattern.toString() !== str);
    } else {
      delete this._callingHandlers[method.toLowerCase()];
    }
    return this;
  }
};
var RPC = _RPC;
RPC.Error = RPCError;

// src/index.rn.ts
import { Base64 } from "js-base64";

// src/SmartRPC.ts
function SmartifyInstance(target, options) {
  const rpc = target;
  const rpcHandler = {
    get(target2, prop) {
      if (typeof prop !== "string") {
        return target2[prop];
      }
      if (Reflect.has(target2, prop)) {
        return target2[prop];
      } else if (!Reflect.has(target2.$cache, prop)) {
        target2.$cache[prop] = new Proxy(
          Object.assign(() => {
          }, {
            $rpcMethod: target2.$rpcMethod.length > 0 ? `${target2.$rpcMethod}.${String(prop)}` : String(prop),
            $cache: {}
          }),
          rpcHandler
        );
      }
      return target2.$cache[prop];
    },
    apply(target2, _, params) {
      if (Reflect.has(rpc, target2.$rpcMethod) && rpc[target2.$rpcMethod] instanceof Function) {
        return rpc[target2.$rpcMethod](...params);
      }
      return rpc.call(target2.$rpcMethod, params);
    }
  };
  const $cache = {};
  const { exclude = ["then", "catch", "finally"] } = { ...options };
  return new Proxy(rpc, {
    get(target2, prop) {
      if (Reflect.has(target2, prop) || exclude.includes(prop)) {
        return target2[prop];
      }
      if (!Reflect.has($cache, prop)) {
        $cache[prop] = new Proxy(
          Object.assign(() => {
          }, {
            $rpcMethod: String(prop),
            $cache: {}
          }),
          rpcHandler
        );
      }
      return $cache[prop];
    }
  });
}
function Smartify(target, options) {
  return new Proxy(target, {
    construct(targetClass, args) {
      return SmartifyInstance(Reflect.construct(targetClass, args), options);
    }
  });
}

// src/index.rn.ts
Object.assign(RPC, {
  isBuffer: (value) => value instanceof ArrayBuffer || toString.call(value) === "[object ArrayBuffer]",
  bufferEncode: (value) => Base64.btoa(String.fromCharCode(...new Uint8Array(value))),
  bufferDecode: (s) => {
    const value = Base64.atob(s);
    const arr = new Uint8Array(value.length);
    return arr.map((_, i) => value.charCodeAt(i)).buffer;
  }
});
var index_rn_default = RPC;
export {
  RPC,
  RPCError,
  RPCResult,
  Smartify,
  SmartifyInstance,
  index_rn_default as default
};
