async-post-message
Version:
Asynchronous postMessage protocol for typed, promise-based windows and iFrame communication
154 lines (150 loc) • 4.6 kB
JavaScript
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/ParentHandler.ts
var handleWebViewRequest = (target, handler) => {
const handleMessage = (event) => __async(void 0, null, function* () {
const response = yield handler(event.data);
target.postMessage(response, "*");
});
window.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
};
};
// src/utils/index.ts
var generateAlphaNumericUniqueId = () => {
const randomNumber = Math.floor(Math.random() * 36);
const timestamp = Date.now();
const uniqueId = `${randomNumber}-${timestamp}`;
const alphaNumericUniqueId = uniqueId.replace(/[\W_]/g, "");
return alphaNumericUniqueId;
};
// src/RequestManager/RequestManager.ts
var RequestManager = class {
constructor() {
/**
* Send a strongly typed async postMessage request.
*
* @param functionName The name of the function to call
* @param args The arguments to pass to the function
* @param options Options for the request. Defaults to a timeout of 10 seconds. If `0` is passed
* as the timeout, the request will not timeout.
* @returns A promise that resolves with the return value of the function
*/
this.send = (functionName, args, options) => {
const uid = generateAlphaNumericUniqueId();
const promise = new Promise(
(resolve, reject) => {
var _a;
this.callbacks.set(uid, { resolve, reject });
const message = {
uid,
functionName,
args
};
this.postMessage(message);
const timeout = (_a = options == null ? void 0 : options.timeoutMs) != null ? _a : 1e4;
if (timeout > 0) {
setTimeout(() => {
reject(new Error(`${functionName} timed out (id: ${uid})`));
this.callbacks.delete(uid);
}, timeout);
}
}
);
return promise;
};
this.callbacks = /* @__PURE__ */ new Map();
}
/**
* Handler for postMessages to the client.
*
* @param message Message payload received by the webview.
*/
onResponse(message) {
const callback = this.callbacks.get(message.uid);
if (!callback) {
return;
}
this.callbacks.delete(message.uid);
if (message.error) {
callback.reject(new Error(message.error));
} else {
callback.resolve(message.response);
}
}
/**
* Send a strongly typed async postMessage request to the target. This should be set by the
* client.
*
* @param _message Message payload to send to the target.
*/
postMessage(_message) {
console.warn("[AsyncPostMessage] postMessage unimplemented");
}
};
// src/WebViewRequester.ts
var _WebViewRequester = class _WebViewRequester {
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
constructor() {
/**
* Execute a strongly typed promise that is executed in the parent process.
*/
this.execute = (functionName, args, options) => {
return this.requestManager.send(functionName, args, options);
};
this.requestManager = new RequestManager();
window.addEventListener(
"message",
(event) => {
if (!event.data) {
return;
}
this.requestManager.onResponse(event.data);
}
);
this.requestManager.postMessage = (message) => {
window.parent.postMessage(message, "*");
};
}
};
/**
* The static method that controls the access to the global AsyncPostMessage instance.
*
* We use a singleton so that the client does not need to worry about creating multiple
* instances of the `AsyncPostMessage` class.
*/
_WebViewRequester.getInstance = () => {
if (!_WebViewRequester.instance) {
_WebViewRequester.instance = new _WebViewRequester();
}
return _WebViewRequester.instance;
};
var WebViewRequester = _WebViewRequester;
export {
RequestManager,
WebViewRequester,
handleWebViewRequest
};
//# sourceMappingURL=index.mjs.map