@steambrew/client
Version:
A support library for creating plugins with Millennium.
185 lines (157 loc) • 5 kB
text/typescript
/** Returnable IPC types */
type IPC_types = string | number | boolean;
/*
Global Millennium API for developers.
*/
type Millennium = {
/**
* Call a method on the backend
* @deprecated Use `callable` instead.
* Example usage:
* ```typescript
* // before
* const result = await Millennium.callServerMethod('methodName', { arg1: 'value' });
* // after
* const method = callable<[{ arg1: string }]>("methodName");
*
* const result1 = await method({ arg1: 'value1' });
* const result2 = await method({ arg1: 'value2' });
* ```
*/
callServerMethod: (methodName: string, kwargs?: object) => Promise<any>;
findElement: (privateDocument: Document, querySelector: string, timeOut?: number) => Promise<NodeListOf<Element>>;
exposeObj?: <T extends object>(obj: T) => any;
AddWindowCreateHook?: (callback: (context: object) => void) => void;
};
/**
* Make reusable IPC call declarations
*
* frontend:
* ```typescript
* const method = callable<[{ arg1: string }]>("methodName"); // declare the method
* method({ arg1: 'value' }); // call the method
* ```
*
* backend:
* ```python
* def methodName(arg1: str):
* pass
* ```
*/
declare const callable: <Args extends any[] = [], T = IPC_types>(route: string) => (...args: Args) => Promise<T>;
const m_private_context: any = undefined;
export const pluginSelf = m_private_context;
declare global {
interface Window {
Millennium: Millennium;
MILLENNIUM_CHROME_DEV_TOOLS_PROTOCOL_DO_NOT_USE_OR_OVERRIDE_ONMESSAGE: any;
CHROME_DEV_TOOLS_PROTOCOL_API_BINDING: MillenniumChromeDevToolsProtocol;
}
}
declare const BindPluginSettings: () => any;
interface FileInfo {
content: string;
filePath: string;
fileName: string;
}
type BufferEncoding = 'ascii' | 'utf8' | 'utf-8' | 'utf16le' | 'ucs2' | 'ucs-2' | 'base64' | 'latin1' | 'binary' | 'hex';
interface SingleFileExprProps {
basePath?: string;
encoding?: BufferEncoding;
}
interface MultiFileExprProps {
basePath?: string;
include?: string; // A regex pattern to include files
encoding?: BufferEncoding;
}
/**
* Create a compile time filesystem expression.
* This function will evaluate a file path at compile time, and embed a files content statically into the bundle.
*/
declare const constSysfsExpr: {
(fileName: string, props: SingleFileExprProps): FileInfo;
(props: MultiFileExprProps): FileInfo[];
};
interface CDPMessage {
id?: number;
method: string;
params?: Record<string, any>;
sessionId?: string; // Optional session ID for targeted commands
result?: any;
error?: {
message: string;
code: number;
};
}
class MillenniumChromeDevToolsProtocol {
devTools: any;
currentId: number;
pendingRequests: Map<number, { resolve: (value: any) => void; reject: (reason?: any) => void }>;
constructor() {
this.devTools = window.MILLENNIUM_CHROME_DEV_TOOLS_PROTOCOL_DO_NOT_USE_OR_OVERRIDE_ONMESSAGE;
this.currentId = 0;
this.pendingRequests = new Map();
// Override the onmessage callback to handle responses
this.devTools.onmessage = (message: any) => {
this.handleMessage(message);
};
}
handleMessage(message: any) {
const data = typeof message === 'string' ? JSON.parse(message) : message;
// Check if this is a response to one of our requests
if (data.id !== undefined && this.pendingRequests.has(data.id)) {
const pending = this.pendingRequests.get(data.id);
this.pendingRequests.delete(data.id);
if (pending) {
const { resolve, reject } = pending;
if (data.error) {
reject(new Error(`CDP Error: ${data.error.message} (${data.error.code})`));
} else {
resolve(data.result);
}
}
}
}
send(method: string, params: any = {}, sessionId?: string) {
return new Promise((resolve, reject) => {
const id = this.currentId++;
// Store the promise resolvers
this.pendingRequests.set(id, { resolve, reject });
// Prepare the message
const message: CDPMessage = {
id: id,
method: method,
};
// Only add params if they're provided and not empty
if (params && Object.keys(params).length > 0) {
message.params = params;
}
// If a sessionId is provided, include it in the message
if (sessionId) {
message.sessionId = sessionId;
}
// Send the message
try {
this.devTools.send(JSON.stringify(message));
} catch (error) {
// Clean up if send fails
this.pendingRequests.delete(id);
reject(error);
}
});
}
// Helper method to send without waiting for response (fire and forget)
sendNoResponse(method: string, params = {}) {
const message: CDPMessage = {
id: this.currentId++,
method: method,
};
if (params && Object.keys(params).length > 0) {
message.params = params;
}
this.devTools.send(JSON.stringify(message));
}
}
const ChromeDevToolsProtocol: MillenniumChromeDevToolsProtocol = new MillenniumChromeDevToolsProtocol();
const Millennium: Millennium = window.Millennium;
export { ChromeDevToolsProtocol, Millennium, callable, BindPluginSettings, constSysfsExpr };