UNPKG

figwire

Version:

Bidirectional IPC communication between UI and core in Figma plugins. Lightweight and typed.

123 lines (117 loc) 3.99 kB
var __defProp$1 = Object.defineProperty; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value); var _a; _a = Symbol.toStringTag; class DeferredPromise { constructor() { __publicField$1(this, _a, "Promise"); __publicField$1(this, "_promise"); __publicField$1(this, "resolve", () => void 0); __publicField$1(this, "reject", () => void 0); this._promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); } // biome-ignore lint/suspicious/noThenProperty: this class overwrites Promise. then(onFulfilled, onRejected) { return this._promise.then(onFulfilled, onRejected); } catch(onRejected) { return this._promise.catch(onRejected); } finally(onFinally) { return this._promise.finally(onFinally); } } function hash() { let count = 0; return { create() { return ++count; } }; } const isRequestMessage = (message) => message.type === "request"; const isResponseMessage = (message) => message.type === "response"; const isErrorMessage = (message) => message.type === "error"; var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); class API { constructor(name, postFn, receiveFn, options = { silentError: false }) { this.name = name; this.postFn = postFn; this.receiveFn = receiveFn; this.options = options; __publicField(this, "requestQueue", /* @__PURE__ */ new Map()); __publicField(this, "callbacks", /* @__PURE__ */ new Map()); __publicField(this, "hasher", hash()); this.receiveFn(async (message) => { if (isRequestMessage(message)) { const methodName = message.name.split("")[0]; const method = this.callbacks.get(methodName); if (!method) { const message2 = `Method "${methodName}" is not defined on "${this.name}" API. (Maybe typo?)`; if (!this.options.silentError) { throw new Error(message2); } console.error(message2); return; } try { const result = await Promise.resolve(method(...message.args)); this.postFn({ type: "response", name: message.name, return: result }); } catch (error) { if (error instanceof Error) { this.postFn({ type: "error", name: message.name, message: error.message }); } } } if (isErrorMessage(message)) { const promise = this.requestQueue.get(message.name); if (!promise) return; promise.reject(message.message); this.requestQueue.delete(message.name); } if (isResponseMessage(message)) { const promise = this.requestQueue.get(message.name); if (!promise) return; promise.resolve(message.return); this.requestQueue.delete(message.name); } }); } async request(name, args) { const hash2 = this.hasher.create(); const requestName = `${name}${hash2}`; const promise = new DeferredPromise(); this.requestQueue.set(requestName, promise); this.postFn({ type: "request", name: requestName, args: args || [] }); return promise; } registerMethod(name, callback) { this.callbacks.set(name, callback); } } function createClient(api) { return new Proxy({}, { get(_, prop) { return async (...args) => api.request(prop, args); } }); } export { API as A, createClient as c };