trpc-chrome
Version:
tRPC adapter for Web Extensions
156 lines • 6.37 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createChromeHandler = void 0;
const server_1 = require("@trpc/server");
const observable_1 = require("@trpc/server/observable");
const errors_1 = require("./errors");
const createChromeHandler = (opts) => {
const { router, createContext, onError } = opts;
const { transformer } = router._def._config;
chrome.runtime.onConnect.addListener((port) => {
const subscriptions = new Map();
const listeners = [];
const onDisconnect = () => {
listeners.forEach((unsub) => unsub());
};
port.onDisconnect.addListener(onDisconnect);
listeners.push(() => port.onDisconnect.removeListener(onDisconnect));
const onMessage = async (message) => {
if (!('trpc' in message))
return;
const { trpc } = message;
if (!('id' in trpc) || trpc.id === null || trpc.id === undefined)
return;
if (!trpc)
return;
const { id, jsonrpc, method } = trpc;
const sendResponse = (response) => {
port.postMessage({
trpc: Object.assign({ id, jsonrpc }, response),
});
};
let params;
let input;
let ctx;
try {
if (method === 'subscription.stop') {
const subscription = subscriptions.get(id);
if (subscription) {
subscription.unsubscribe();
sendResponse({
result: {
type: 'stopped',
},
});
}
subscriptions.delete(id);
return;
}
params = trpc.params;
input = transformer.input.deserialize(params.input);
ctx = await (createContext === null || createContext === void 0 ? void 0 : createContext({ req: port, res: undefined }));
const caller = router.createCaller(ctx);
const segments = params.path.split('.');
const procedureFn = segments.reduce((acc, segment) => acc[segment], caller);
const result = await procedureFn(input);
if (method !== 'subscription') {
const data = transformer.output.serialize(result);
sendResponse({
result: {
type: 'data',
data,
},
});
return;
}
if (!(0, observable_1.isObservable)(result)) {
throw new server_1.TRPCError({
message: 'Subscription ${params.path} did not return an observable',
code: 'INTERNAL_SERVER_ERROR',
});
}
const subscription = result.subscribe({
next: (data) => {
sendResponse({
result: {
type: 'data',
data,
},
});
},
error: (cause) => {
const error = (0, errors_1.getErrorFromUnknown)(cause);
onError === null || onError === void 0 ? void 0 : onError({
error,
type: method,
path: params === null || params === void 0 ? void 0 : params.path,
input,
ctx,
req: port,
});
sendResponse({
error: router.getErrorShape({
error,
type: method,
path: params === null || params === void 0 ? void 0 : params.path,
input,
ctx,
}),
});
},
complete: () => {
sendResponse({
result: {
type: 'stopped',
},
});
},
});
if (subscriptions.has(id)) {
subscription.unsubscribe();
sendResponse({
result: {
type: 'stopped',
},
});
throw new server_1.TRPCError({
message: `Duplicate id ${id}`,
code: 'BAD_REQUEST',
});
}
listeners.push(() => subscription.unsubscribe());
subscriptions.set(id, subscription);
sendResponse({
result: {
type: 'started',
},
});
return;
}
catch (cause) {
const error = (0, errors_1.getErrorFromUnknown)(cause);
onError === null || onError === void 0 ? void 0 : onError({
error,
type: method,
path: params === null || params === void 0 ? void 0 : params.path,
input,
ctx,
req: port,
});
sendResponse({
error: router.getErrorShape({
error,
type: method,
path: params === null || params === void 0 ? void 0 : params.path,
input,
ctx,
}),
});
}
};
port.onMessage.addListener(onMessage);
listeners.push(() => port.onMessage.removeListener(onMessage));
});
};
exports.createChromeHandler = createChromeHandler;
//# sourceMappingURL=index.js.map