UNPKG

@stolbivi/pirojok

Version:

Some minimalistic library used to build chrome extensions, covers some popular Chrome Extension API

225 lines (224 loc) 9.04 kB
"use strict"; /** * Type definitions and utilities for Chrome extension messaging system. * Provides a type-safe way to handle request-response style communication between different parts of a Chrome extension. */ var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Messages = exports.createFromRequest = exports.createAction = exports.createRequest = void 0; /** * Creates a request creator function for a specific message type * @template Payload - Type of the request payload * @template Response - Type of the expected response * @param type - Unique identifier for the request type * @returns A function that creates requests of the specified type */ function createRequest(type) { function create(payload) { var request = { type: type, payload: payload, }; return __assign(__assign({}, request), { toAction: function () { return request; } }); } create.toString = function () { return "".concat(type); }; create.type = type; return create; } exports.createRequest = createRequest; /** * Creates an action creator function for handling specific message types * @template Payload - Type of the action payload * @template Response - Type of the response to be sent back * @param type - Unique identifier for the action type * @param handler - Function that will handle the incoming message * @returns A function that creates actions of the specified type */ function createAction(type, handler) { function create(payload) { return { type: type, payload: payload !== null && payload !== void 0 ? payload : undefined, handler: handler, }; } create.toString = function () { return "".concat(type); }; create.type = type; return create; } exports.createAction = createAction; /** * Creates an action creator from an existing request creator * @template Payload - Type of the payload * @template Response - Type of the response * @param requestCreator - The request creator to base the action on * @param handler - Function that will handle the incoming message * @returns A function that creates actions matching the request type */ function createFromRequest(requestCreator, handler) { function create(payload) { return { type: requestCreator.type, payload: payload, handler: handler, }; } create.toString = function () { return "".concat(requestCreator.type); }; create.type = requestCreator.type; return create; } exports.createFromRequest = createFromRequest; /** * Enhanced messaging API wrapper for Chrome extensions. * Provides a type-safe way to handle request-response communication between different parts of the extension. * Automatically cleans up listeners after receiving a response or on failure. */ var Messages = /** @class */ (function () { /** * Creates a new Messages instance * @param verbose - Whether to enable verbose logging */ function Messages(verbose) { if (verbose === void 0) { verbose = false; } this._verbose = verbose; } /** * Sends a request to the extension runtime * @template Payload - Type of the request payload * @template Response - Type of the expected response * @param request - The request to send * @returns Promise that resolves with the response or rejects with an error */ Messages.prototype.request = function (request) { return this.handleRequest(request, chrome.runtime.connect({ name: request.type })); }; /** * Sends a request to a specific tab * @template Payload - Type of the request payload * @template Response - Type of the expected response * @param tabId - ID of the target tab * @param request - The request to send * @returns Promise that resolves with the response or rejects with an error */ Messages.prototype.requestTab = function (tabId, request) { return this.handleRequest(request, chrome.tabs.connect(tabId, { name: request.type })); }; /** * Handles the request-response cycle for a given port * @template Payload - Type of the request payload * @template Response - Type of the expected response * @param request - The request to send * @param port - The port to communicate through * @returns Promise that resolves with the response or rejects with an error */ Messages.prototype.handleRequest = function (request, port) { var _this = this; return new Promise(function (resolve, reject) { var onDisconnect = function () { try { if (chrome.runtime.lastError) { reject(chrome.runtime.lastError.message); } } catch (e) { reject('Error handling runtime error: ' + JSON.stringify(e)); } if (_this._verbose) { console.debug('Removing onDisconnect listener for:', request.type); } port.onDisconnect.removeListener(onDisconnect); }; port.onDisconnect.addListener(onDisconnect); var onMessage = function (response) { resolve(response); if (_this._verbose) { console.debug('Removing onMessage listener for:', request.type); } port.onMessage.removeListener(onMessage); }; port.onMessage.addListener(onMessage); try { port.postMessage(request.payload); } catch (e) { reject('Error posting message: ' + JSON.stringify(e)); } }); }; /** * Sets up a listener for incoming connections of a specific type * @template Payload - Type of the incoming message payload * @template Response - Type of the response to be sent back * @param actionCreator - Function that creates actions for handling messages * @returns The connection listener function that was added */ Messages.prototype.listen = function (actionCreator) { var _this = this; var onConnect = function (port) { var action = actionCreator(); if (port.name === action.type) { var onMessage_1 = function (payload) { action .handler(payload, port.sender) .then(function (response) { try { port.postMessage(response); } catch (e) { console.error('Error posting response:', JSON.stringify(e)); } }) .then(function () { if (_this._verbose) { console.debug('Listener completed for:', port.name); } }) .catch(function (e) { return console.error(e); }) .finally(function () { if (_this._verbose) { console.debug('Disconnecting port and removing listener'); } port.disconnect(); port.onMessage.removeListener(onMessage_1); }); }; if (_this._verbose) { console.debug('Adding listener for port:', port.name); } port.onMessage.addListener(onMessage_1); var onDisconnect_1 = function (p) { if (_this._verbose) { console.debug('Disconnect detected for:', p.name, 'removing listeners'); } p.onMessage.removeListener(onMessage_1); p.onDisconnect.removeListener(onDisconnect_1); }; port.onDisconnect.addListener(onDisconnect_1); } }; chrome.runtime.onConnect.addListener(onConnect); return onConnect; }; /** * Removes a previously added connection listener * @param onConnect - The listener function to remove */ Messages.prototype.removeListener = function (onConnect) { if (this._verbose) { console.debug('Removing listener'); } chrome.runtime.onConnect.removeListener(onConnect); }; return Messages; }()); exports.Messages = Messages;