@chord-ts/rpc
Version:
💎 Cutting edge transport framework vanishing borders between frontend and backend
147 lines (146 loc) • 5.63 kB
JavaScript
"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _RPC_transport, _RPC_format;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Builder = exports.RPC = void 0;
exports.client = client;
const defaults_1 = require("./defaults");
const specs_1 = require("../specs");
function client(init) {
const rpc = new RPC(init);
const builder = new Builder(rpc);
return builder;
}
class RPC {
constructor({ endpoint, config, options }) {
_RPC_transport.set(this, void 0);
_RPC_format.set(this, void 0);
if (!endpoint) {
throw Error('No RPC endpoint was provided');
}
this.endpoint = endpoint;
const proto = Reflect.getPrototypeOf(this);
this.internal = new Set([...Reflect.ownKeys(proto), ...Reflect.ownKeys(this)]);
__classPrivateFieldSet(this, _RPC_transport, config?.transport ?? defaults_1.defaultTransport, "f");
__classPrivateFieldSet(this, _RPC_format, config?.format ?? {
parse: (r) => r.json(),
stringify: (r) => JSON.stringify(r)
}, "f");
this.errorCallback = config?.onError ?? defaults_1.defaultOnError;
this.cacheStorage = config?.cache ?? defaults_1.defaultCache;
this.options = options ?? {};
}
get transport() {
return __classPrivateFieldGet(this, _RPC_transport, "f");
}
get format() {
return __classPrivateFieldGet(this, _RPC_format, "f");
}
isInternal(prop) {
return this.internal.has(prop);
}
async call({ method, params }) {
const body = (0, specs_1.buildRequest)({ method, params });
const res = await this.transport({ route: this.endpoint, body, format: this.format }, this.options ?? {});
if (res.error) {
await this.errorCallback(res.error, body);
return;
}
return res.result;
}
chainUpdate(override) {
const newRPC = new RPC({
endpoint: this.endpoint,
config: { ...this.currentConfig, ...override.config },
options: { ...this.options, ...override.options }
});
return new Builder(newRPC);
}
get currentConfig() {
return {
transport: this.transport,
onError: this.errorCallback,
cache: this.cacheStorage
};
}
config(config) {
return this.chainUpdate({ config });
}
abort(signal) {
return this.chainUpdate({ options: { signal } });
}
opt(options) {
return this.chainUpdate({ options });
}
pipe() {
throw Error('Not implemented');
}
async batch(...calls) {
const res = (await this.transport({ route: this.endpoint, body: calls }));
return res.map((r, i) => {
if (r?.error) {
this.errorCallback(r.error, calls[i]);
}
return r.result;
});
}
cache(config) {
const { get, set } = this.cacheStorage(config);
return function (method) {
return async function (...params) {
const cached = get({ method, params });
if (config?.mode !== 'update' && cached)
return cached;
const res = this.call(method)(params).then((res) => {
set({ method, params }, res);
return res;
});
return cached ?? res;
};
};
}
}
exports.RPC = RPC;
_RPC_transport = new WeakMap(), _RPC_format = new WeakMap();
class Builder extends Function {
constructor(rpc, path = []) {
super();
const proto = Reflect.getPrototypeOf(this);
this.internal = new Set([...Reflect.ownKeys(proto), ...Reflect.ownKeys(this)]);
this.path = path;
this.rpc = rpc;
return new Proxy(this, this);
}
get readyMethod() {
return this.path.join('.');
}
isInternal(prop) {
return this.internal.has(prop);
}
apply(target, thisArg, argArray) {
return this.rpc.call({ method: this.readyMethod, params: argArray });
}
get(target, prop) {
if (this.isInternal(prop) && !this.path.length) {
return this[prop];
}
else if (this.rpc.isInternal(prop) && !this.path.length) {
return this.rpc[prop];
}
return new Builder(this.rpc, this.path.concat(prop));
}
construct(target, args) {
return (0, specs_1.buildRequest)({ method: this.readyMethod, params: args });
}
}
exports.Builder = Builder;