computers
Version:
computer←→computer
127 lines (121 loc) • 3.01 kB
JavaScript
;
// src/caller.ts
async function call(api, path, args) {
const paths = path.split(".");
let value = api;
for (const path2 of paths) {
if (typeof value !== "object" || value === null) {
throw new Error("Invalid path");
}
if (!(path2 in value)) {
throw new Error("Invalid path");
}
value = value[path2];
}
if (typeof value !== "function") {
throw new Error("Invalid path");
}
try {
const result = await value(...args);
return {
success: true,
data: result
};
} catch (error) {
return {
success: false,
message: error instanceof Error ? error.message : "Unknown error"
// TODO: BAD!
};
}
}
// src/constants.ts
var SYMBOL_TRANSPORT_UNSUBSCRIBE = Symbol(
"computers:transport-unsubscribe"
);
// src/utils.ts
function nonce() {
return Math.random().toString(36).substring(2, 15);
}
function deferred() {
let resolve;
const promise = new Promise((res) => {
resolve = res;
});
return {
promise,
resolve
};
}
// src/transport.ts
function createTransport(transport) {
const pending = /* @__PURE__ */ new Map();
const unsubscribe = transport.subscribe(async (message) => {
if (message.type === "response") {
const resolve = pending.get(message.nonce);
if (!resolve) {
return;
}
pending.delete(message.nonce);
resolve(message);
} else {
await transport.call(message.path, message.args).then(
(result) => transport.send({
type: "response",
nonce: message.nonce,
...result
}),
(error) => transport.send({
type: "response",
nonce: message.nonce,
message: error instanceof Error ? error.message : String(error),
success: false
})
);
}
});
const handle = {
unsubscribe,
call: (path, args) => {
const { promise, resolve } = deferred();
const id = nonce();
pending.set(id, resolve);
transport.send({
type: "request",
nonce: id,
path,
args
});
return promise;
}
};
function proxy(path) {
return new Proxy(() => {
}, {
get: function(_, prop) {
if (prop === SYMBOL_TRANSPORT_UNSUBSCRIBE) {
return handle.unsubscribe;
}
if (typeof prop === "symbol") {
throw new Error("Symbol not supported");
}
const prefix = path ? `${path}.` : "";
const newPath = `${prefix}${prop}`;
return proxy(newPath);
},
apply: async function(_target, _, args) {
const result = await handle.call(path, args);
if (!result.success) {
throw new Error(result.message);
}
return result.data;
}
});
}
return proxy("");
}
exports.SYMBOL_TRANSPORT_UNSUBSCRIBE = SYMBOL_TRANSPORT_UNSUBSCRIBE;
exports.call = call;
exports.createTransport = createTransport;
exports.deferred = deferred;
exports.nonce = nonce;