Build cross-platform desktop apps with JavaScript, HTML, and CSS
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Network requests, custom protocol registration, and session management for handling web resources and custom schemes.
HTTP/HTTPS requests using Chromium's network stack.
/**
* Issue HTTP/HTTPS requests using Chromium's native networking library
*/
interface Net {
/** Creates a ClientRequest instance using the provided options */
request(options: ClientRequestConstructorOptions | string): ClientRequest;
/** A convenience method which creates a ClientRequest and automatically loads the response */
fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
/** Whether there is currently internet connection */
isOnline(): boolean;
/** Resolves with the IP address of the given hostname */
resolveHost(hostname: string, options?: ResolveHostOptions): Promise<ResolvedHost>;
}
declare const net: Net;
/**
* ClientRequest implements the Writable Stream interface and is an EventEmitter
*/
interface ClientRequest extends NodeJS.WritableStream {
/** Adds an HTTP header */
setHeader(name: string, value: string): void;
/** Returns the value of a previously set header name */
getHeader(name: string): string | undefined;
/** Removes a previously set header name */
removeHeader(name: string): void;
/** Adds an HTTP header */
getHeaders(): Record<string, string>;
/** Finishes sending the request */
end(chunk?: string | Buffer, encoding?: string): this;
/** Aborts the ongoing HTTP transaction */
abort(): void;
/** Returns the method of the request */
getMethod(): string;
/** Returns the URL of the request */
getURL(): string;
/** Returns an object containing the request headers */
getRawHeaderList(): Array<{ name: string; value: string }>;
/** Whether the request will use chunked transfer encoding */
chunkedEncoding: boolean;
}Usage Examples:
const { net } = require('electron');
// Simple GET request
async function fetchData(url) {
try {
const response = await net.fetch(url);
const data = await response.json();
console.log('Data:', data);
return data;
} catch (error) {
console.error('Fetch error:', error);
throw error;
}
}
// POST request with data
async function postData(url, payload) {
try {
const response = await net.fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + getAuthToken()
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('POST error:', error);
throw error;
}
}
// Using ClientRequest directly
function makeRequest(url, options = {}) {
return new Promise((resolve, reject) => {
const request = net.request({
method: options.method || 'GET',
url: url,
headers: options.headers || {}
});
request.on('response', (response) => {
let data = '';
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', () => {
try {
const parsed = JSON.parse(data);
resolve(parsed);
} catch (error) {
resolve(data);
}
});
});
request.on('error', (error) => {
reject(error);
});
if (options.body) {
request.write(options.body);
}
request.end();
});
}
// Check network connectivity
function checkConnectivity() {
const isOnline = net.isOnline();
console.log('Network status:', isOnline ? 'Online' : 'Offline');
return isOnline;
}Custom protocol scheme handling for app-specific URLs.
/**
* Register a custom protocol and intercept existing protocol requests
*/
interface Protocol {
/** Registers the scheme as standard, secure, bypasses content security policy for resources, allows registering ServiceWorker, supports fetch API, streaming video/audio, and V8 code cache */
registerSchemesAsPrivileged(customSchemes: CustomScheme[]): void;
/** Registers a protocol of scheme that will send a file as the response */
handle(scheme: string, handler: ProtocolHandler): void;
/** Unregisters the custom scheme of scheme */
unhandle(scheme: string): void;
/** Whether the scheme is already handled */
isProtocolHandled(scheme: string): boolean;
}
declare const protocol: Protocol;
type ProtocolHandler = (request: ProtocolRequest) => Promise<ProtocolResponse> | ProtocolResponse;
interface ProtocolRequest {
url: string;
referrer: string;
method: string;
headers: Record<string, string>;
uploadData?: UploadData[];
}
interface ProtocolResponse {
statusCode?: number;
headers?: Record<string, string>;
data?: Buffer | string;
path?: string;
mimeType?: string;
charset?: string;
}Usage Examples:
const { protocol, app } = require('electron');
const path = require('path');
const fs = require('fs');
// Register custom protocol before app is ready
app.whenReady().then(() => {
// Register a custom protocol for serving app files
protocol.handle('myapp', (request) => {
const url = request.url.slice('myapp://'.length);
const filePath = path.join(__dirname, 'assets', url);
return {
path: filePath
};
});
// Register API protocol
protocol.handle('myapi', async (request) => {
const url = new URL(request.url);
const endpoint = url.pathname;
try {
switch (endpoint) {
case '/users':
const users = await getUsersFromDatabase();
return {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
data: JSON.stringify(users)
};
case '/config':
const config = getAppConfiguration();
return {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
data: JSON.stringify(config)
};
default:
return {
statusCode: 404,
data: 'Not Found'
};
}
} catch (error) {
return {
statusCode: 500,
data: error.message
};
}
});
});
// Register schemes as privileged (must be done before app ready)
protocol.registerSchemesAsPrivileged([
{
scheme: 'myapp',
privileges: {
standard: true,
secure: true,
supportsFetchAPI: true,
corsEnabled: true
}
},
{
scheme: 'myapi',
privileges: {
standard: true,
secure: true,
supportsFetchAPI: true
}
}
]);
// Usage in renderer
// You can now use: myapp://index.html or myapi://usersBrowser session management including cookies, cache, and network behavior.
/**
* Manage browser sessions, cookies, cache, proxy settings, etc.
*/
interface Session extends EventEmitter {
/** Creates a session instance from partition string */
static fromPartition(partition: string, options?: FromPartitionOptions): Session;
/** A session instance from the default partition which is used by BrowserWindows by default */
static readonly defaultSession: Session;
/** The cookies instance for this session */
readonly cookies: Cookies;
/** The webRequest instance for this session */
readonly webRequest: WebRequest;
/** The protocol instance for this session */
readonly protocol: Protocol;
/** The netLog instance for this session */
readonly netLog: NetLog;
/** A convenience method; creates a ClientRequest and automatically loads the response */
fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
/** Sets the proxy settings */
setProxy(config: ProxyConfig): Promise<void>;
/** Resolves the proxy information for url */
resolveProxy(url: string): Promise<string>;
/** Sets download saving directory */
setDownloadPath(path: string): void;
/** Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate authentication */
enableNetworkEmulation(options: NetworkEmulationOptions): void;
/** Disables any network emulation already active for the session */
disableNetworkEmulation(): void;
/** Sets the certificate verify proc for session */
setCertificateVerifyProc(proc: CertificateVerifyProc | null): void;
/** Sets the handler which can be used to respond to permission requests for the session */
setPermissionRequestHandler(handler: PermissionRequestHandler | null): void;
/** Sets the handler which can be used to respond to permission checks for the session */
setPermissionCheckHandler(handler: PermissionCheckHandler | null): void;
/** Sets the handler which can be used to respond to display media requests */
setDisplayMediaRequestHandler(handler: DisplayMediaRequestHandler | null, options?: DisplayMediaRequestHandlerHandlerOptions): void;
/** Clears the session's HTTP cache */
clearCache(): Promise<void>;
/** Clears the session's HTTP authentication cache */
clearAuthCache(): Promise<void>;
/** Clears the session's storage data */
clearStorageData(options?: ClearStorageDataOptions): Promise<void>;
/** Allows resuming cancelled or interrupted downloads from previous Session */
createInterruptedDownload(options: CreateInterruptedDownloadOptions): void;
/** Clears the host resolver cache */
clearHostResolverCache(): Promise<void>;
/** Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate authentication */
allowNTLMCredentialsForDomains(domains: string): void;
/** Sets the proxy settings */
setUserAgent(userAgent: string, acceptLanguages?: string): void;
/** Returns the user agent for this session */
getUserAgent(): string;
/** Returns all extension that are loaded in this session */
getAllExtensions(): Record<string, Extension>;
/** Returns the extension with the given ID */
getExtension(extensionId: string): Extension | null;
/** Removes an extension */
removeExtension(extensionId: string): void;
/** Loads an extension */
loadExtension(path: string, options?: LoadExtensionOptions): Promise<Extension>;
/** Sets the BrowserWindow to be used for DevTools inspection */
setDevToolsWebContents(webContents: WebContents): void;
/** Sets the proxy settings */
getBlobData(identifier: string): Promise<Buffer>;
/** Downloads the file from url to targetPath */
downloadURL(url: string): void;
/** Sets code cache directory */
setCodeCachePath(path: string): void;
/** Returns path to the code cache directory if available */
getCodeCachePath(): string | null;
/** Returns availablility of spellchecker */
availableSpellCheckerLanguages: string[];
/** A boolean indicating whether builtin spell checker is enabled */
spellCheckerEnabled: boolean;
/** An array of language codes the spell checker is set to */
listWordsInSpellCheckerDictionary(): Promise<string[]>;
/** Adds a word to the custom dictionary */
addWordToSpellCheckerDictionary(word: string): boolean;
/** Removes a word from the custom dictionary */
removeWordFromSpellCheckerDictionary(word: string): boolean;
/** Loads a Hunspell dictionary for the language defined by languageCode */
loadExtension(path: string): Promise<Extension>;
/** Sets the spellchecker provider */
setSpellCheckerDictionaryDownloadURL(url: string): void;
/** Returns path where Hunspell dictionaries are stored */
getSpellCheckerDictionaryDownloadURL(): string;
/** A string indicating the absolute file system path where data for this session is persisted on disk */
readonly storagePath: string | null;
/** A boolean indicating whether the session is persistent or temporary */
readonly isPersistent: boolean;
}Usage Examples:
const { session, BrowserWindow } = require('electron');
// Work with default session
const defaultSession = session.defaultSession;
// Create custom session
const customSession = session.fromPartition('custom-session', {
cache: false // In-memory session
});
// Set proxy
async function setupProxy() {
await defaultSession.setProxy({
proxyRules: 'http://proxy.example.com:8080',
proxyBypassRules: 'localhost,127.0.0.1'
});
}
// Handle downloads
defaultSession.on('will-download', (event, item, webContents) => {
// Set download path
item.setSavePath('/tmp/' + item.getFilename());
item.on('updated', (event, state) => {
if (state === 'interrupted') {
console.log('Download is interrupted but can be resumed');
} else if (state === 'progressing') {
if (item.isPaused()) {
console.log('Download is paused');
} else {
console.log(`Received bytes: ${item.getReceivedBytes()}`);
}
}
});
item.once('done', (event, state) => {
if (state === 'completed') {
console.log('Download successfully');
} else {
console.log(`Download failed: ${state}`);
}
});
});
// Handle permissions
defaultSession.setPermissionRequestHandler((webContents, permission, callback) => {
const allowedPermissions = ['notifications', 'microphone', 'camera'];
if (allowedPermissions.includes(permission)) {
callback(true);
} else {
callback(false);
}
});
// Cookie management
async function manageCookies() {
const cookies = defaultSession.cookies;
// Set a cookie
await cookies.set({
url: 'https://example.com',
name: 'session_id',
value: 'abc123',
secure: true,
httpOnly: true
});
// Get cookies
const allCookies = await cookies.get({});
console.log('All cookies:', allCookies);
// Remove cookie
await cookies.remove('https://example.com', 'session_id');
}
// Clear data
async function clearSessionData() {
await defaultSession.clearStorageData({
storages: ['cookies', 'localStorage', 'sessionStorage', 'caches'],
quotas: ['temporary', 'persistent', 'syncable']
});
await defaultSession.clearCache();
}interface ClientRequestConstructorOptions {
method?: string;
url?: string;
session?: Session;
partition?: string;
credentials?: 'include' | 'omit' | 'same-origin';
useSessionCookies?: boolean;
protocol?: string;
host?: string;
hostname?: string;
port?: number;
path?: string;
redirect?: 'follow' | 'error' | 'manual';
origin?: string;
cache?: 'default' | 'no-store' | 'reload' | 'no-cache' | 'force-cache' | 'only-if-cached';
}
interface CustomScheme {
scheme: string;
privileges?: {
standard?: boolean;
secure?: boolean;
bypassCSP?: boolean;
allowServiceWorkers?: boolean;
supportsFetchAPI?: boolean;
corsEnabled?: boolean;
stream?: boolean;
codeCache?: boolean;
};
}
interface UploadData {
contentType: string;
data: string | Buffer;
encoding?: string;
boundary?: string;
}
interface ResolveHostOptions {
queryType?: 'A' | 'AAAA';
source?: 'any' | 'system' | 'dns' | 'mdns' | 'localOnly';
cacheUsage?: 'allowed' | 'staleAllowed' | 'disallowed';
secureDnsPolicy?: 'allow' | 'disable';
}
interface ResolvedHost {
addresses: string[];
canonicalName?: string;
}
interface FromPartitionOptions {
cache?: boolean;
}
interface ProxyConfig {
mode?: 'direct' | 'auto_detect' | 'pac_script' | 'fixed_servers' | 'system';
pacScript?: string;
proxyRules?: string;
proxyBypassRules?: string;
}
interface NetworkEmulationOptions {
offline?: boolean;
latency?: number;
downloadThroughput?: number;
uploadThroughput?: number;
}
interface ClearStorageDataOptions {
origin?: string;
storages?: string[];
quotas?: string[];
}
interface CreateInterruptedDownloadOptions {
path: string;
urlChain: string[];
mimeType?: string;
offset: number;
length: number;
lastModified?: string;
eTag?: string;
startTime?: number;
}
interface LoadExtensionOptions {
allowFileAccess?: boolean;
}
interface Extension {
id: string;
name: string;
url: string;
version: string;
path?: string;
}
interface DisplayMediaRequestHandlerHandlerOptions {
useSystemPicker?: boolean;
}
type CertificateVerifyProc = (request: CertificateVerifyProcRequest, callback: (verificationResult: number) => void) => void;
type PermissionRequestHandler = (webContents: WebContents, permission: Permission, callback: (permissionGranted: boolean) => void, details: PermissionRequestHandlerHandlerDetails) => void;
type PermissionCheckHandler = (webContents: WebContents | null, permission: string, requestingOrigin: string, details: PermissionCheckHandlerHandlerDetails) => boolean;
type DisplayMediaRequestHandler = (request: DisplayMediaRequestHandlerRequest, callback: (streams: Streams) => void) => void;
interface CertificateVerifyProcRequest {
hostname: string;
certificate: Certificate;
validatedCertificate: Certificate;
isIssuedByKnownRoot: boolean;
verificationResult: string;
errorCode: number;
}
type Permission = 'clipboard-read' | 'media' | 'mediaKeySystem' | 'geolocation' | 'notifications' | 'midi' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' | 'unknown';
interface PermissionRequestHandlerHandlerDetails {
externalURL?: string;
mediaTypes?: Array<'video' | 'audio'>;
requestingUrl: string;
isMainFrame: boolean;
}
interface PermissionCheckHandlerHandlerDetails {
requestingUrl: string;
isMainFrame: boolean;
securityOrigin: string;
mediaType?: 'video' | 'audio';
}
interface DisplayMediaRequestHandlerRequest {
frame: WebFrameMain;
securityOrigin: string;
videoRequested: boolean;
audioRequested: boolean;
userGesture: boolean;
}
interface Streams {
video?: {
id: string;
name: string;
};
audio?: {
id: string;
name: string;
};
}Install with Tessl CLI
npx tessl i tessl/npm-electron