aboutsummaryrefslogtreecommitdiff
path: root/ext/js/app
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2023-12-29 19:17:46 -0500
committerGitHub <noreply@github.com>2023-12-30 00:17:46 +0000
commit7303da3991814a0ce220bf2fff3e51b968913b86 (patch)
tree809c289d824ec2a08c5ff54579766b7f5c5e09e1 /ext/js/app
parent1b0e0c551d1505ed4242c04ebac224e5fff81f04 (diff)
Cross frame API safety (#491)
* Require error type * Add TODOs * Fix init * Updates * More type safety * Fix incorrect API map * Update type safety * Updates * Add API * Update types * Update types * Updates * Remove unused * Restore types * Update frame ancestry handler * Simplify names * Fix * Remove old message handlers
Diffstat (limited to 'ext/js/app')
-rw-r--r--ext/js/app/frontend.js42
-rw-r--r--ext/js/app/popup-factory.js105
-rw-r--r--ext/js/app/popup-proxy.js48
-rw-r--r--ext/js/app/popup-window.js34
-rw-r--r--ext/js/app/popup.js32
5 files changed, 104 insertions, 157 deletions
diff --git a/ext/js/app/frontend.js b/ext/js/app/frontend.js
index e386bf64..9dafde7a 100644
--- a/ext/js/app/frontend.js
+++ b/ext/js/app/frontend.js
@@ -178,11 +178,11 @@ export class Frontend {
/* eslint-disable no-multi-spaces */
yomitan.crossFrame.registerHandlers([
- ['Frontend.closePopup', this._onApiClosePopup.bind(this)],
- ['Frontend.copySelection', this._onApiCopySelection.bind(this)],
- ['Frontend.getSelectionText', this._onApiGetSelectionText.bind(this)],
- ['Frontend.getPopupInfo', this._onApiGetPopupInfo.bind(this)],
- ['Frontend.getPageInfo', this._onApiGetPageInfo.bind(this)]
+ ['frontendClosePopup', this._onApiClosePopup.bind(this)],
+ ['frontendCopySelection', this._onApiCopySelection.bind(this)],
+ ['frontendGetSelectionText', this._onApiGetSelectionText.bind(this)],
+ ['frontendGetPopupInfo', this._onApiGetPopupInfo.bind(this)],
+ ['frontendGetPageInfo', this._onApiGetPageInfo.bind(this)]
]);
/* eslint-enable no-multi-spaces */
@@ -263,48 +263,31 @@ export class Frontend {
// API message handlers
- /**
- * @returns {string}
- */
- _onApiGetUrl() {
- return window.location.href;
- }
-
- /**
- * @returns {void}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'frontendClosePopup'>} */
_onApiClosePopup() {
this._clearSelection(false);
}
- /**
- * @returns {void}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'frontendCopySelection'>} */
_onApiCopySelection() {
// This will not work on Firefox if a popup has focus, which is usually the case when this function is called.
document.execCommand('copy');
}
- /**
- * @returns {string}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'frontendGetSelectionText'>} */
_onApiGetSelectionText() {
const selection = document.getSelection();
return selection !== null ? selection.toString() : '';
}
- /**
- * @returns {import('frontend').GetPopupInfoResult}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'frontendGetPopupInfo'>} */
_onApiGetPopupInfo() {
return {
popupId: (this._popup !== null ? this._popup.id : null)
};
}
- /**
- * @returns {{url: string, documentTitle: string}}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'frontendGetPageInfo'>} */
_onApiGetPageInfo() {
return {
url: window.location.href,
@@ -620,8 +603,7 @@ export class Frontend {
return await this._getDefaultPopup();
}
- /** @type {import('frontend').GetPopupInfoResult} */
- const {popupId} = await yomitan.crossFrame.invoke(targetFrameId, 'Frontend.getPopupInfo', {});
+ const {popupId} = await yomitan.crossFrame.invoke(targetFrameId, 'frontendGetPopupInfo', void 0);
if (popupId === null) {
return null;
}
@@ -905,7 +887,7 @@ export class Frontend {
let documentTitle = document.title;
if (this._useProxyPopup && this._parentFrameId !== null) {
try {
- ({url, documentTitle} = await yomitan.crossFrame.invoke(this._parentFrameId, 'Frontend.getPageInfo', {}));
+ ({url, documentTitle} = await yomitan.crossFrame.invoke(this._parentFrameId, 'frontendGetPageInfo', void 0));
} catch (e) {
// NOP
}
diff --git a/ext/js/app/popup-factory.js b/ext/js/app/popup-factory.js
index 184a55ca..0d8cabd4 100644
--- a/ext/js/app/popup-factory.js
+++ b/ext/js/app/popup-factory.js
@@ -49,21 +49,21 @@ export class PopupFactory {
this._frameOffsetForwarder.prepare();
/* eslint-disable no-multi-spaces */
yomitan.crossFrame.registerHandlers([
- ['PopupFactory.getOrCreatePopup', this._onApiGetOrCreatePopup.bind(this)],
- ['PopupFactory.setOptionsContext', this._onApiSetOptionsContext.bind(this)],
- ['PopupFactory.hide', this._onApiHide.bind(this)],
- ['PopupFactory.isVisible', this._onApiIsVisibleAsync.bind(this)],
- ['PopupFactory.setVisibleOverride', this._onApiSetVisibleOverride.bind(this)],
- ['PopupFactory.clearVisibleOverride', this._onApiClearVisibleOverride.bind(this)],
- ['PopupFactory.containsPoint', this._onApiContainsPoint.bind(this)],
- ['PopupFactory.showContent', this._onApiShowContent.bind(this)],
- ['PopupFactory.setCustomCss', this._onApiSetCustomCss.bind(this)],
- ['PopupFactory.clearAutoPlayTimer', this._onApiClearAutoPlayTimer.bind(this)],
- ['PopupFactory.setContentScale', this._onApiSetContentScale.bind(this)],
- ['PopupFactory.updateTheme', this._onApiUpdateTheme.bind(this)],
- ['PopupFactory.setCustomOuterCss', this._onApiSetCustomOuterCss.bind(this)],
- ['PopupFactory.getFrameSize', this._onApiGetFrameSize.bind(this)],
- ['PopupFactory.setFrameSize', this._onApiSetFrameSize.bind(this)]
+ ['popupFactoryGetOrCreatePopup', this._onApiGetOrCreatePopup.bind(this)],
+ ['popupFactorySetOptionsContext', this._onApiSetOptionsContext.bind(this)],
+ ['popupFactoryHide', this._onApiHide.bind(this)],
+ ['popupFactoryIsVisible', this._onApiIsVisibleAsync.bind(this)],
+ ['popupFactorySetVisibleOverride', this._onApiSetVisibleOverride.bind(this)],
+ ['popupFactoryClearVisibleOverride', this._onApiClearVisibleOverride.bind(this)],
+ ['popupFactoryContainsPoint', this._onApiContainsPoint.bind(this)],
+ ['popupFactoryShowContent', this._onApiShowContent.bind(this)],
+ ['popupFactorySetCustomCss', this._onApiSetCustomCss.bind(this)],
+ ['popupFactoryClearAutoPlayTimer', this._onApiClearAutoPlayTimer.bind(this)],
+ ['popupFactorySetContentScale', this._onApiSetContentScale.bind(this)],
+ ['popupFactoryUpdateTheme', this._onApiUpdateTheme.bind(this)],
+ ['popupFactorySetCustomOuterCss', this._onApiSetCustomOuterCss.bind(this)],
+ ['popupFactoryGetFrameSize', this._onApiGetFrameSize.bind(this)],
+ ['popupFactorySetFrameSize', this._onApiSetFrameSize.bind(this)]
]);
/* eslint-enable no-multi-spaces */
}
@@ -152,7 +152,7 @@ export class PopupFactory {
}
const useFrameOffsetForwarder = (parentPopupId === null);
/** @type {{id: string, depth: number, frameId: number}} */
- const info = await yomitan.crossFrame.invoke(frameId, 'PopupFactory.getOrCreatePopup', /** @type {import('popup-factory').GetOrCreatePopupDetails} */ ({
+ const info = await yomitan.crossFrame.invoke(frameId, 'popupFactoryGetOrCreatePopup', /** @type {import('popup-factory').GetOrCreatePopupDetails} */ ({
id,
parentPopupId,
frameId,
@@ -239,10 +239,7 @@ export class PopupFactory {
// API message handlers
- /**
- * @param {import('popup-factory').GetOrCreatePopupDetails} details
- * @returns {Promise<{id: string, depth: number, frameId: number}>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactoryGetOrCreatePopup'>} */
async _onApiGetOrCreatePopup(details) {
const popup = await this.getOrCreatePopup(details);
return {
@@ -252,53 +249,37 @@ export class PopupFactory {
};
}
- /**
- * @param {{id: string, optionsContext: import('settings').OptionsContext}} params
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactorySetOptionsContext'>} */
async _onApiSetOptionsContext({id, optionsContext}) {
const popup = this._getPopup(id);
await popup.setOptionsContext(optionsContext);
}
- /**
- * @param {{id: string, changeFocus: boolean}} params
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactoryHide'>} */
async _onApiHide({id, changeFocus}) {
const popup = this._getPopup(id);
await popup.hide(changeFocus);
}
- /**
- * @param {{id: string}} params
- * @returns {Promise<boolean>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactoryIsVisible'>} */
async _onApiIsVisibleAsync({id}) {
const popup = this._getPopup(id);
return await popup.isVisible();
}
- /**
- * @param {{id: string, value: boolean, priority: number}} params
- * @returns {Promise<?import('core').TokenString>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactorySetVisibleOverride'>} */
async _onApiSetVisibleOverride({id, value, priority}) {
const popup = this._getPopup(id);
return await popup.setVisibleOverride(value, priority);
}
- /**
- * @param {{id: string, token: import('core').TokenString}} params
- * @returns {Promise<boolean>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactoryClearVisibleOverride'>} */
async _onApiClearVisibleOverride({id, token}) {
const popup = this._getPopup(id);
return await popup.clearVisibleOverride(token);
}
- /**
- * @param {{id: string, x: number, y: number}} params
- * @returns {Promise<boolean>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactoryContainsPoint'>} */
async _onApiContainsPoint({id, x, y}) {
const popup = this._getPopup(id);
const offset = this._getPopupOffset(popup);
@@ -307,10 +288,7 @@ export class PopupFactory {
return await popup.containsPoint(x, y);
}
- /**
- * @param {{id: string, details: import('popup').ContentDetails, displayDetails: ?import('display').ContentDetails}} params
- * @returns {Promise<void>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactoryShowContent'>} */
async _onApiShowContent({id, details, displayDetails}) {
const popup = this._getPopup(id);
if (!this._popupCanShow(popup)) { return; }
@@ -327,64 +305,43 @@ export class PopupFactory {
return await popup.showContent(details, displayDetails);
}
- /**
- * @param {{id: string, css: string}} params
- * @returns {Promise<void>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactorySetCustomCss'>} */
async _onApiSetCustomCss({id, css}) {
const popup = this._getPopup(id);
await popup.setCustomCss(css);
}
- /**
- * @param {{id: string}} params
- * @returns {Promise<void>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactoryClearAutoPlayTimer'>} */
async _onApiClearAutoPlayTimer({id}) {
const popup = this._getPopup(id);
await popup.clearAutoPlayTimer();
}
- /**
- * @param {{id: string, scale: number}} params
- * @returns {Promise<void>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactorySetContentScale'>} */
async _onApiSetContentScale({id, scale}) {
const popup = this._getPopup(id);
await popup.setContentScale(scale);
}
- /**
- * @param {{id: string}} params
- * @returns {Promise<void>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactoryUpdateTheme'>} */
async _onApiUpdateTheme({id}) {
const popup = this._getPopup(id);
await popup.updateTheme();
}
- /**
- * @param {{id: string, css: string, useWebExtensionApi: boolean}} params
- * @returns {Promise<void>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactorySetCustomOuterCss'>} */
async _onApiSetCustomOuterCss({id, css, useWebExtensionApi}) {
const popup = this._getPopup(id);
await popup.setCustomOuterCss(css, useWebExtensionApi);
}
- /**
- * @param {{id: string}} params
- * @returns {Promise<import('popup').ValidSize>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactoryGetFrameSize'>} */
async _onApiGetFrameSize({id}) {
const popup = this._getPopup(id);
return await popup.getFrameSize();
}
- /**
- * @param {{id: string, width: number, height: number}} params
- * @returns {Promise<boolean>}
- */
+ /** @type {import('cross-frame-api').ApiHandler<'popupFactorySetFrameSize'>} */
async _onApiSetFrameSize({id, width, height}) {
const popup = this._getPopup(id);
return await popup.setFrameSize(width, height);
diff --git a/ext/js/app/popup-proxy.js b/ext/js/app/popup-proxy.js
index 2821d774..e581be82 100644
--- a/ext/js/app/popup-proxy.js
+++ b/ext/js/app/popup-proxy.js
@@ -140,7 +140,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<void>}
*/
async setOptionsContext(optionsContext) {
- await this._invokeSafe('PopupFactory.setOptionsContext', {id: this._id, optionsContext}, void 0);
+ await this._invokeSafe('popupFactorySetOptionsContext', {id: this._id, optionsContext}, void 0);
}
/**
@@ -149,7 +149,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<void>}
*/
async hide(changeFocus) {
- await this._invokeSafe('PopupFactory.hide', {id: this._id, changeFocus}, void 0);
+ await this._invokeSafe('popupFactoryHide', {id: this._id, changeFocus}, void 0);
}
/**
@@ -157,7 +157,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<boolean>} `true` if the popup is visible, `false` otherwise.
*/
isVisible() {
- return this._invokeSafe('PopupFactory.isVisible', {id: this._id}, false);
+ return this._invokeSafe('popupFactoryIsVisible', {id: this._id}, false);
}
/**
@@ -168,7 +168,7 @@ export class PopupProxy extends EventDispatcher {
* or null if the override wasn't assigned.
*/
setVisibleOverride(value, priority) {
- return this._invokeSafe('PopupFactory.setVisibleOverride', {id: this._id, value, priority}, null);
+ return this._invokeSafe('popupFactorySetVisibleOverride', {id: this._id, value, priority}, null);
}
/**
@@ -177,7 +177,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<boolean>} `true` if the override existed and was removed, `false` otherwise.
*/
clearVisibleOverride(token) {
- return this._invokeSafe('PopupFactory.clearVisibleOverride', {id: this._id, token}, false);
+ return this._invokeSafe('popupFactoryClearVisibleOverride', {id: this._id, token}, false);
}
/**
@@ -192,7 +192,7 @@ export class PopupProxy extends EventDispatcher {
x += this._frameOffsetX;
y += this._frameOffsetY;
}
- return await this._invokeSafe('PopupFactory.containsPoint', {id: this._id, x, y}, false);
+ return await this._invokeSafe('popupFactoryContainsPoint', {id: this._id, x, y}, false);
}
/**
@@ -212,7 +212,7 @@ export class PopupProxy extends EventDispatcher {
sourceRect.bottom += this._frameOffsetY;
}
}
- await this._invokeSafe('PopupFactory.showContent', {id: this._id, details, displayDetails}, void 0);
+ await this._invokeSafe('popupFactoryShowContent', {id: this._id, details, displayDetails}, void 0);
}
/**
@@ -221,7 +221,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<void>}
*/
async setCustomCss(css) {
- await this._invokeSafe('PopupFactory.setCustomCss', {id: this._id, css}, void 0);
+ await this._invokeSafe('popupFactorySetCustomCss', {id: this._id, css}, void 0);
}
/**
@@ -229,7 +229,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<void>}
*/
async clearAutoPlayTimer() {
- await this._invokeSafe('PopupFactory.clearAutoPlayTimer', {id: this._id}, void 0);
+ await this._invokeSafe('popupFactoryClearAutoPlayTimer', {id: this._id}, void 0);
}
/**
@@ -238,7 +238,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<void>}
*/
async setContentScale(scale) {
- await this._invokeSafe('PopupFactory.setContentScale', {id: this._id, scale}, void 0);
+ await this._invokeSafe('popupFactorySetContentScale', {id: this._id, scale}, void 0);
}
/**
@@ -254,7 +254,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<void>}
*/
async updateTheme() {
- await this._invokeSafe('PopupFactory.updateTheme', {id: this._id}, void 0);
+ await this._invokeSafe('popupFactoryUpdateTheme', {id: this._id}, void 0);
}
/**
@@ -265,7 +265,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<void>}
*/
async setCustomOuterCss(css, useWebExtensionApi) {
- await this._invokeSafe('PopupFactory.setCustomOuterCss', {id: this._id, css, useWebExtensionApi}, void 0);
+ await this._invokeSafe('popupFactorySetCustomOuterCss', {id: this._id, css, useWebExtensionApi}, void 0);
}
/**
@@ -282,7 +282,7 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<import('popup').ValidSize>} The size and whether or not it is valid.
*/
getFrameSize() {
- return this._invokeSafe('PopupFactory.getFrameSize', {id: this._id}, {width: 0, height: 0, valid: false});
+ return this._invokeSafe('popupFactoryGetFrameSize', {id: this._id}, {width: 0, height: 0, valid: false});
}
/**
@@ -292,32 +292,28 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<boolean>} `true` if the size assignment was successful, `false` otherwise.
*/
setFrameSize(width, height) {
- return this._invokeSafe('PopupFactory.setFrameSize', {id: this._id, width, height}, false);
+ return this._invokeSafe('popupFactorySetFrameSize', {id: this._id, width, height}, false);
}
// Private
- // TODO : Type safety
/**
- * @template {import('core').SerializableObject} TParams
- * @template [TReturn=unknown]
- * @param {string} action
- * @param {TParams} params
- * @returns {Promise<TReturn>}
+ * @template {import('cross-frame-api').ApiNames} TName
+ * @param {TName} action
+ * @param {import('cross-frame-api').ApiParams<TName>} params
+ * @returns {Promise<import('cross-frame-api').ApiReturn<TName>>}
*/
_invoke(action, params) {
return yomitan.crossFrame.invoke(this._frameId, action, params);
}
- // TODO : Type safety
/**
- * @template {import('core').SerializableObject} TParams
- * @template [TReturn=unknown]
+ * @template {import('cross-frame-api').ApiNames} TName
* @template [TReturnDefault=unknown]
- * @param {string} action
- * @param {TParams} params
+ * @param {TName} action
+ * @param {import('cross-frame-api').ApiParams<TName>} params
* @param {TReturnDefault} defaultReturnValue
- * @returns {Promise<TReturn|TReturnDefault>}
+ * @returns {Promise<import('cross-frame-api').ApiReturn<TName>|TReturnDefault>}
*/
async _invokeSafe(action, params, defaultReturnValue) {
try {
diff --git a/ext/js/app/popup-window.js b/ext/js/app/popup-window.js
index 801afb3f..a696885a 100644
--- a/ext/js/app/popup-window.js
+++ b/ext/js/app/popup-window.js
@@ -126,7 +126,7 @@ export class PopupWindow extends EventDispatcher {
* @returns {Promise<void>}
*/
async setOptionsContext(optionsContext) {
- await this._invoke(false, 'displaySetOptionsContext', {id: this._id, optionsContext});
+ await this._invoke(false, 'displaySetOptionsContext', {optionsContext});
}
/**
@@ -183,7 +183,7 @@ export class PopupWindow extends EventDispatcher {
*/
async showContent(_details, displayDetails) {
if (displayDetails === null) { return; }
- await this._invoke(true, 'displaySetContent', {id: this._id, details: displayDetails});
+ await this._invoke(true, 'displaySetContent', {details: displayDetails});
}
/**
@@ -192,7 +192,7 @@ export class PopupWindow extends EventDispatcher {
* @returns {Promise<void>}
*/
async setCustomCss(css) {
- await this._invoke(false, 'displaySetCustomCss', {id: this._id, css});
+ await this._invoke(false, 'displaySetCustomCss', {css});
}
/**
@@ -200,7 +200,7 @@ export class PopupWindow extends EventDispatcher {
* @returns {Promise<void>}
*/
async clearAutoPlayTimer() {
- await this._invoke(false, 'displayAudioClearAutoPlayTimer', {id: this._id});
+ await this._invoke(false, 'displayAudioClearAutoPlayTimer', void 0);
}
/**
@@ -266,24 +266,29 @@ export class PopupWindow extends EventDispatcher {
// Private
- // TODO : Type safety
/**
- * @template {import('core').SerializableObject} TParams
- * @template [TReturn=unknown]
+ * @template {import('display').DirectApiNames} TName
* @param {boolean} open
- * @param {string} action
- * @param {TParams} params
- * @returns {Promise<TReturn|undefined>}
+ * @param {TName} action
+ * @param {import('display').DirectApiParams<TName>} params
+ * @returns {Promise<import('display').DirectApiReturn<TName>|undefined>}
*/
async _invoke(open, action, params) {
if (yomitan.isExtensionUnloaded) {
return void 0;
}
+ const message = /** @type {import('display').DirectApiMessageAny} */ ({action, params});
+
const frameId = 0;
if (this._popupTabId !== null) {
try {
- return await yomitan.crossFrame.invokeTab(this._popupTabId, frameId, 'popupMessage', {action, params});
+ return /** @type {import('display').DirectApiReturn<TName>} */ (await yomitan.crossFrame.invokeTab(
+ this._popupTabId,
+ frameId,
+ 'displayPopupMessage2',
+ message
+ ));
} catch (e) {
if (yomitan.isExtensionUnloaded) {
open = false;
@@ -299,6 +304,11 @@ export class PopupWindow extends EventDispatcher {
const {tabId} = await yomitan.api.getOrCreateSearchPopup({focus: 'ifCreated'});
this._popupTabId = tabId;
- return await yomitan.crossFrame.invokeTab(this._popupTabId, frameId, 'popupMessage', {action, params});
+ return /** @type {import('display').DirectApiReturn<TName>} */ (await yomitan.crossFrame.invokeTab(
+ this._popupTabId,
+ frameId,
+ 'displayPopupMessage2',
+ message
+ ));
}
}
diff --git a/ext/js/app/popup.js b/ext/js/app/popup.js
index a8cdf1a6..0f7fbd87 100644
--- a/ext/js/app/popup.js
+++ b/ext/js/app/popup.js
@@ -316,7 +316,7 @@ export class Popup extends EventDispatcher {
*/
async clearAutoPlayTimer() {
if (this._frameConnected) {
- await this._invokeSafe('displayAudioClearAutoPlayTimer', {});
+ await this._invokeSafe('displayAudioClearAutoPlayTimer', void 0);
}
}
@@ -679,13 +679,11 @@ export class Popup extends EventDispatcher {
}
}
- // TODO : Type safety
/**
- * @template {import('core').SerializableObject} TParams
- * @template [TReturn=unknown]
- * @param {string} action
- * @param {TParams} params
- * @returns {Promise<TReturn>}
+ * @template {import('display').DirectApiNames} TName
+ * @param {TName} action
+ * @param {import('display').DirectApiParams<TName>} params
+ * @returns {Promise<import('display').DirectApiReturn<TName>>}
*/
async _invoke(action, params) {
const contentWindow = this._frame.contentWindow;
@@ -693,17 +691,21 @@ export class Popup extends EventDispatcher {
throw new Error(`Failed to invoke action ${action}: frame state invalid`);
}
- const message = this._frameClient.createMessage({action, params});
- return await yomitan.crossFrame.invoke(this._frameClient.frameId, 'popupMessage', message);
+ /** @type {import('display').DirectApiMessage<TName>} */
+ const message = {action, params};
+ const wrappedMessage = this._frameClient.createMessage(message);
+ return /** @type {import('display').DirectApiReturn<TName>} */ (await yomitan.crossFrame.invoke(
+ this._frameClient.frameId,
+ 'displayPopupMessage1',
+ /** @type {import('display').DirectApiFrameClientMessageAny} */ (wrappedMessage)
+ ));
}
- // TODO : Type safety
/**
- * @template {import('core').SerializableObject} TParams
- * @template [TReturn=unknown]
- * @param {string} action
- * @param {TParams} params
- * @returns {Promise<TReturn|undefined>}
+ * @template {import('display').DirectApiNames} TName
+ * @param {TName} action
+ * @param {import('display').DirectApiParams<TName>} params
+ * @returns {Promise<import('display').DirectApiReturn<TName>|undefined>}
*/
async _invokeSafe(action, params) {
try {