UNPKG

@chord-ts/rpc

Version:

💎 Cutting edge transport framework vanishing borders between frontend and backend

147 lines (146 loc) • 5.63 kB
"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;