@trt-web/browser
v1.1.2
Published
Framework-free wrappers for modern browser APIs and web platform features.
Maintainers
Keywords
Readme
@trt-web/browser
Introduction
@trt-web/browseris a framework-agnostic TypeScript toolkit for working with modern browser APIs and Web Platform features.It provides focused, strongly typed wrappers for media, audio, storage, permissions, speech, networking, window management, device APIs, and browser-native AI capabilities where supported. The APIs are designed to stay close to the Web Platform while providing a consistent and reusable interface for common browser interactions.
Use
@trt-web/browserto build dashboards, PWAs, productivity tools, media experiences, and other modern browser-based applications.
Why @trt-web/browser?
- Framework-agnostic and suitable for TypeScript or JavaScript applications.
- Strongly typed APIs built around native browser capabilities.
- Modular utilities that can be adopted independently.
- Explicit handling for unsupported APIs and permission-based features.
Install
- Install the package using your preferred package manager:
npm install @trt-web/browseryarn add @trt-web/browserbun add @trt-web/browserCLI
- The package includes trt-browser, an interactive CLI for discovering available utilities, exploring methods and usage examples, and generating static documentation from the package README.
npx trt-browser
npx trt-browser --list
npx trt-browser info BrowserCamera # or any available utility name
npx trt-browser docsFor Contributors
All contributions are welcome.
If you find a bug, want to improve an existing API, or have an idea for a new Web Platform utility, please see
CONTRIBUTING.mdfor contribution guidelines, testing expectations, and pull request requirements.Contact:
- Github: therightthings/trt-web
- NPM: @trt-web/browser
- Email: [email protected] (Nam Nguyen)
BrowserAI
Built-in browser AI helpers.
Methods
isSupported(): boolean: check whether at least one supported built-in browser AI API is available.isLanguageDetectorSupported(): boolean: check Language Detector API support.isPromptSupported(): boolean: check Prompt API support.isSummarizerSupported(): boolean: check Summarizer API support.isTranslatorSupported(): boolean: check Translator API support.supportedFeatures(): BrowserAISupportedFeatures: return support status for each built-in AI feature.detectAvailability(): Promise<BrowserAIAvailability>: check Language Detector model availability. The result isunavailable,downloadable,downloading, oravailable.summarizeAvailability(options?): Promise<BrowserAIAvailability>: check Summarizer model availability before creating a session. The result isunavailable,downloadable,downloading, oravailable.translateAvailability(options?): Promise<BrowserAIAvailability>: check Translator model availability before creating a session. The result isunavailable,downloadable,downloading, oravailable.detectLanguage(input: string, options?: { signal?: AbortSignal; onProgress?: BrowserAIProgressHandler }): Promise<BrowserAIDetection[]>: detect languages and confidence scores from text.signalcancels the operation andonProgressreceives download, processing, and completion events.promptAvailability(options?: { expectedInputs?: BrowserAILanguageFormat[]; expectedOutputs?: BrowserAILanguageFormat[] }): Promise<BrowserAIAvailability>: check Prompt API model availability for the requested input and output formats. The result isunavailable,downloadable,downloading, oravailable.createPromptSession(options?: BrowserAIPromptCreateOptions): Promise<BrowserAISession>: create a reusable Prompt API session.expectedInputsandexpectedOutputsdescribe supported formats,initialPromptsseeds system/user/assistant messages,signalcancels model creation, andonProgressreports download progress. Callsession.destroy()when it is no longer needed.prompt(input: string, options?: BrowserAIPromptCreateOptions & BrowserAIPromptOptions): Promise<string>: generate one complete response. Supports prompt formats,initialPrompts,signal, andonProgress.promptStreaming(input: string, options?: BrowserAIPromptCreateOptions & BrowserAIPromptOptions): Promise<ReadableStream<string>>: generate a response incrementally with the same prompt options. Cancel the reader or abort the supplied signal to stop it; the session is destroyed automatically after completion, error, or cancellation.summarize(input: string, options?: BrowserAISummarizeOptions): Promise<string>: summarize text with the selected format and length.signalcancels model creation or the response, andonProgressreports download, processing, and completion events.summarizeStreaming(input: string, options?: BrowserAISummarizeOptions): Promise<ReadableStream<string>>: return summary chunks as a stream. Cancel the reader or suppliedsignalto destroy the native session.translate(input: string, options: BrowserAITranslateOptions): Promise<string>: translate text between the selected source and target languages.signalcancels model creation or the response, andonProgressreports download, processing, and completion events.translateStreaming(input: string, options: BrowserAITranslateOptions): Promise<ReadableStream<string>>: return translated chunks as a stream. Cancel the reader or suppliedsignalto destroy the native session.
Examples
- Translation, summary, prompt, and response streaming:
import { BrowserAI, readStream } from '@trt-web/browser';
if (BrowserAI.isTranslatorSupported()) {
const availability = await BrowserAI.translateAvailability({
sourceLanguage: 'en',
targetLanguage: 'vi',
});
if (availability === 'available') {
const translated = await BrowserAI.translate('Hello from the browser', {
sourceLanguage: 'en',
targetLanguage: 'vi',
onProgress: (progress) => {
console.log(progress.phase, `${Math.round(progress.progress * 100)}%`);
/**
* downloading 50%
* processing 0%
* done 100%
*/
},
});
console.log(translated);
}
}
const detections = await BrowserAI.detectLanguage('Bonjour tout le monde', {
onProgress: (progress) => {
console.log(progress.phase, `${Math.round(progress.progress * 100)}%`);
},
});
console.log(detections);
const summary = await BrowserAI.summarize('Long text...', {
format: 'plain-text',
length: 'short',
onProgress: (progress) => {
console.log(progress.phase, `${Math.round(progress.progress * 100)}%`);
},
});
console.log(summary);
const prompt = await BrowserAI.prompt('Summarize this release note', {
initialPrompts: [{ role: 'system', content: 'Answer in concise bullet points.' }],
expectedOutputs: [{ type: 'text', languages: ['en'] }],
onProgress: (progress) => console.log(progress.phase, progress.progress),
});
console.log(prompt);
const session = await BrowserAI.createPromptSession({
initialPrompts: [{ role: 'system', content: 'You are a helpful assistant.' }],
});
console.log(await session.prompt('What is a service worker?'));
console.log(await session.prompt('How does it handle offline requests?'));
session.destroy();
const controller = new AbortController();
const response = await BrowserAI.promptStreaming('Explain this API briefly', {
expectedOutputs: [{ type: 'text', languages: ['en'] }],
signal: controller.signal,
});
const text = await readStream(response, {
signal: controller.signal,
onChunk: (chunk) => console.log(chunk),
});
console.log(text);
// To cancel from another event handler at any time:
// controller.abort();
// readStream cancels the underlying reader and releases it automatically.- Streaming summaries and translations:
import { BrowserAI, readStream } from '@trt-web/browser';
const streamedSummary = await readStream(
await BrowserAI.summarizeStreaming('Long text...', {
format: 'plain-text',
length: 'short',
}),
{
onChunk: (chunk) => console.log(chunk), // render this chunk immediately
},
);
const streamedTranslation = await readStream(
await BrowserAI.translateStreaming('Hello from the browser', {
sourceLanguage: 'en',
targetLanguage: 'vi',
}),
{
onChunk: (chunk) => console.log(chunk), // render this chunk immediately
},
);
console.log(streamedSummary, streamedTranslation);Stream
Stream helpers for BrowserAI responses and fetch response bodies.
readStream
Read and combine string or UTF-8 byte chunks into one string. Use onChunk to process each chunk while it arrives. The helper supports AbortSignal and releases the reader after completion, failure, or cancellation. It returns raw response text; parse Server-Sent Events separately when the endpoint uses SSE.
Methods
readStream<T extends string | Uint8Array>(stream: ReadableStream<T>, options?: { onChunk?: (chunk: string) => void | Promise<void>; signal?: AbortSignal }): Promise<string>: read and combine stream chunks as text, optionally processing each chunk as it arrives.
Examples
- Read a BrowserAI streaming response:
import { BrowserAI, readStream } from '@trt-web/browser';
const stream = await BrowserAI.promptStreaming('Explain service workers briefly');
const text = await readStream(stream);
console.log(text);- Read a fetch/OpenAI response through an application proxy:
import { readStream } from '@trt-web/browser';
const controller = new AbortController();
const response = await fetch('/api/openai/stream', {
signal: controller.signal,
});
if (!response.body) {
throw new Error('The response does not contain a readable body.');
}
const rawResponse = await readStream(response.body, {
signal: controller.signal,
});
console.log(rawResponse); // raw text or SSE payload; parse it according to the APIBrowserAudioContext
Web Audio API helpers
Methods
isSupported(): boolean: check whether the Web Audio API is supported.getInstance(): BrowserAudioContext: get the shared audio context manager.ready(options?: AudioContextOptions): Promise<AudioContext | undefined>: resume the audio context when required.getState(): AudioContextState | undefined: read the current AudioContext state.suspend(): Promise<boolean>: suspend all audio processing in the shared context.resume(): Promise<boolean>: resume all audio processing in the shared context.decodeAudioData(data: ArrayBuffer): Promise<AudioBuffer | undefined>: decode an ArrayBuffer into an AudioBuffer.createAudioSession(buffer: AudioBuffer): BrowserAudioSession: create an isolated audio playback session.createToneSession(options: BrowserAudioToneSessionOptions): BrowserAudioTonesSession | undefined: create an isolated oscillator tone session.playTone(options: BrowserAudioToneSessionOptions): Promise<boolean>: play a sequence of oscillator tones.close(): Promise<void>: close the shared audio context.
Examples
import { BrowserAudioContext } from '@trt-web/browser';
if (!BrowserAudioContext.isSupported()) {
throw new Error('Web Audio API is not supported.');
}
const audioContext = BrowserAudioContext.getInstance();
const context = await audioContext.ready({ latencyHint: 'interactive' });
if (!context) {
throw new Error('Could not create AudioContext.');
}
console.log(audioContext.getState()); // running
await audioContext.suspend();
await audioContext.resume();
await audioContext.playTone({
tones: [
{ frequency: 523, type: 'sine', gain: 0.08, durationMs: 90, gapMs: 40 },
{ frequency: 659, type: 'sine', gain: 0.08, durationMs: 120 },
],
});
const file = await fetch('/audio/example.mp3').then((response) => response.blob());
const audioBuffer = await audioContext.decodeAudioData(await file.arrayBuffer());
const audioSession = audioBuffer ? audioContext.createAudioSession(audioBuffer) : undefined;
audioSession?.play();
await new Promise((resolve) => setTimeout(resolve, (audioBuffer?.duration ?? 0) * 1000));
audioSession?.stop();
const toneSession = audioContext.createToneSession({
tones: [
{ frequency: 523, type: 'sine', gain: 0.08, durationMs: 300, gapMs: 40 },
{ frequency: 659, type: 'sine', gain: 0.08, durationMs: 300 },
],
});
toneSession?.createAnalyser({ fftSize: 256, smoothingTimeConstant: 0.8 });
const started = await toneSession?.play();
const frequencyData = toneSession?.getFrequencyData();
const timeDomainData = toneSession?.getTimeDomainData();
console.log(started, toneSession?.state); // true 'playing'
console.log(frequencyData?.length); // analyser.frequencyBinCount
console.log(timeDomainData?.length); // analyser.fftSize
toneSession?.stop();
console.log(toneSession?.state); // 'stopped'
const playbackSession = audioBuffer ? audioContext.createAudioSession(audioBuffer) : undefined;
playbackSession?.play();
playbackSession?.pause();
playbackSession?.resume();
playbackSession?.stop();
playbackSession?.createAnalyser({ fftSize: 2048 });
console.log(playbackSession?.getFrequencyData());
console.log(playbackSession?.getTimeDomainData());
console.log(playbackSession?.getWaveformData({ samples: 500 }));
await audioContext.close();BrowserBattery
Battery status helpers
Methods
isSupported(): boolean: check whether the Battery Status API is available.getState(): Promise<BrowserBatteryState | undefined>: read the current charging status, battery percentage, and estimated times.subscribe(handler: (state: BrowserBatteryState) => void): Promise<BrowserSubscription>: listen for charging, level, charging-time, and discharging-time changes.
Examples
import { BrowserBattery } from '@trt-web/browser';
if (BrowserBattery.isSupported()) {
const state = await BrowserBattery.getState();
console.log(state);
/**
* {
* charging: true,
* percent: 80,
* chargingTimeSeconds: 1800,
* dischargingTimeSeconds: 9007199254740991,
* }
*/
const subscription = await BrowserBattery.subscribe((nextState) => {
console.log(nextState.percent, nextState.charging);
});
subscription.unsubscribe();
}BrowserBluetooth
Web Bluetooth helpers
Methods
isSupported(): boolean: check whether Web Bluetooth is supported.isAvailable(): Promise<boolean>: check whether Bluetooth is currently available.getPairedDevices(): Promise<BrowserBluetoothDevice[]>: list previously permitted Bluetooth devices.requestDevice(options?: BrowserBluetoothRequestOptions): Promise<BrowserBluetoothDevice | undefined>: request a Bluetooth device from the user.connect(device?: BrowserBluetoothDevice): Promise<BrowserBluetoothRemoteGATTServer | undefined>: connect to the device's GATT server.disconnect(): Promise<void>: disconnect from the current GATT server.getDevice(): BrowserBluetoothDevice | undefined: get the currently connected Bluetooth device.getServer(): BrowserBluetoothRemoteGATTServer | undefined: get the currently connected GATT server.getPrimaryService(service: BrowserBluetoothUUID): Promise<BrowserBluetoothRemoteGATTService | undefined>: get a primary GATT service.getCharacteristic(service: BrowserBluetoothUUID, characteristic: BrowserBluetoothUUID): Promise<BrowserBluetoothRemoteGATTCharacteristic | undefined>: get a characteristic from a service.getCharacteristics(service: BrowserBluetoothUUID): Promise<BrowserBluetoothRemoteGATTCharacteristic[]>: list characteristics from a service.readValue(service: BrowserBluetoothUUID, characteristic: BrowserBluetoothUUID): Promise<DataView | undefined>: read a characteristic value.writeValue(payload: BrowserBluetoothWritePayload): Promise<boolean>: write a value to a characteristic.startNotifications(payload: BrowserBluetoothNotificationPayload): Promise<BrowserBluetoothRemoteGATTCharacteristic | undefined>: listen for characteristic value changes.stopNotifications(payload: BrowserBluetoothStopNotificationPayload): void: stop characteristic notifications.
Examples
import { BrowserBluetooth } from '@trt-web/browser';
if (BrowserBluetooth.isSupported() && (await BrowserBluetooth.isAvailable())) {
// Run this from a user gesture, such as a button click.
const device = await BrowserBluetooth.requestDevice({
filters: [{ services: ['heart_rate'] }],
});
const server = await BrowserBluetooth.connect(device);
if (server) {
const value = await BrowserBluetooth.readValue('heart_rate', 'heart_rate_measurement');
console.log(value);
await BrowserBluetooth.disconnect();
}
}BrowserCamera
Camera capture and recording
Methods
isSupported(): boolean: check whether camera capture is supported.facingModes(): Promise<BrowserCameraFacingMode[]>: detect available camera facing modes.listDevices(): Promise<BrowserCameraDevice[]>: list available camera devices.turnOn(options?: BrowserCameraOptions): Promise<BrowserCameraResult>: request and start a camera stream.turnOff(): boolean: stop the current camera stream.createRecorder(options?: BrowserMediaRecorderOptions): Promise<BrowserMediaRecorderSession | undefined>: create an independent recorder session for the camera stream.
Examples
import { BrowserCamera } from '@trt-web/browser';
const video = document.querySelector<HTMLVideoElement>('#camera-preview');
const result = await BrowserCamera.turnOn({ facingMode: 'front' });
if (result.success && video) {
video.srcObject = result.data;
const recorder = await BrowserCamera.createRecorder({ mimeType: 'video/webm' });
recorder?.pause();
recorder?.resume();
const output = await recorder?.stop();
console.log(output?.blob);
BrowserCamera.turnOff();
} else {
console.error('Camera access was denied or is not supported.');
}BrowserClipboard
Clipboard read and write helpers
Methods
isSupported(): boolean: check whether the HTML Canvas API is available.copy(text: string): Promise<ExecuteBrowserServiceResult>: copy text to the clipboard.read(): Promise<string | undefined>: read text from the clipboard.
Examples
import { BrowserClipboard } from '@trt-web/browser';
const copied = await BrowserClipboard.copy('Copied from the browser');
const text = await BrowserClipboard.read();
console.log(copied); // { permission: 'granted', data: 'Copied from the browser', success: true }
console.log(text); // 'Copied from the browser'
const blocked = await BrowserClipboard.copy('Blocked text');
console.log(blocked); // { permission: 'denied', success: false }Canvas
HTML Canvas drawing helpers
Methods
isSupported(): boolean: check whether the HTML Canvas API is available.createSession(canvas?: HTMLCanvasElement): CanvasSession: create an isolatedCanvasSessionfor a canvas element.CanvasSession.getContext(): CanvasRenderingContext2D | undefined: get the session's 2D rendering context.CanvasSession.getSize(): { width: number; height: number }: read the canvas backing-store size.CanvasSession.resize(options?: CanvasResizeOptions): void: resize the canvas, optionally fitting its element or parent and applying device-pixel-ratio scaling.CanvasSession.clear(fillStyle?: string | CanvasGradient | CanvasPattern): void: clear the canvas and optionally fill it with a color.CanvasSession.drawLine(options: CanvasLineOptions): boolean: draw a line with stroke options.CanvasSession.drawRectangle(options: CanvasRectangleOptions): boolean: draw a filled and/or stroked rectangle, optionally with rounded corners.CanvasSession.drawCircle(options: CanvasCircleOptions): boolean: draw a filled and/or stroked circle.CanvasSession.drawText(options: CanvasTextOptions): boolean: draw text with font and alignment options.CanvasSession.drawImage(options: CanvasImageOptions): boolean: draw an image source at a position and optional size.CanvasSession.getImageData(options: CanvasImageDataArea): ImageData | undefined: read pixel data from a rectangular area.CanvasSession.putImageData(imageData: ImageData, options: CanvasPutImageDataOptions): boolean: write pixel data to the canvas.CanvasSession.createGradient(options: CanvasGradientOptions): CanvasGradient | undefined: create a linear or radial gradient.CanvasSession.drawPath(path: Path2D, options?: CanvasPathOptions): boolean: draw or fill aPath2Dpath.CanvasSession.drawPolyline(options: CanvasPolylineOptions): boolean: draw an ordered list of points as an open or closed stroked path.CanvasSession.rotate(angle: number): void: rotate the current drawing transform.CanvasSession.scale(x: number, y: number): void: scale the current drawing transform.CanvasSession.translate(x: number, y: number): void: translate the current drawing transform.CanvasSession.flip(axis: CanvasFlipAxis): void: flip the current drawing transform horizontally or vertically.CanvasSession.resetTransform(): void: reset the current drawing transform.CanvasSession.toBlob(options?: CanvasBlobOptions): Promise<Blob | undefined>: export the canvas as aBlob.CanvasSession.toDataUrl(type?: string, quality?: number): string: export the canvas as a data URL.
Examples
import { Canvas } from '@trt-web/browser';
const session = Canvas.createSession();
session.resize({ height: 180, width: 320 });
session.clear('#172236');
session.drawLine({
start: [16, 16],
end: [180, 80],
strokeStyle: '#7dd3fc',
lineWidth: 4,
});
session.drawText({
text: 'Canvas',
x: 16,
y: 120,
fillStyle: '#e8edf5',
font: '24px sans-serif',
});
const gradient = session.createGradient({
type: 'linear',
x0: 0,
y0: 0,
x1: 320,
y1: 180,
stops: [
{ offset: 0, color: '#0ea5e9' },
{ offset: 1, color: '#8b5cf6' },
],
});
session.drawRectangle({
fillStyle: gradient,
height: 80,
radius: 16,
width: 240,
x: 40,
y: 140,
});
const path = new Path2D();
path.moveTo(40, 260);
path.lineTo(160, 190);
path.lineTo(280, 260);
path.closePath();
session.drawPath(path, { fillStyle: '#1e3a5f', strokeStyle: '#7dd3fc', lineWidth: 2 });
session.drawPolyline({
points: [
[16, 280],
[80, 240],
[160, 280],
],
strokeStyle: '#7dd3fc',
lineCap: 'round',
lineJoin: 'round',
lineWidth: 4,
});
const pixels = session.getImageData({ x: 0, y: 0, width: 20, height: 20 });
if (pixels) {
session.putImageData(pixels, { x: 300, y: 20 });
}
session.translate(160, 90);
session.rotate(Math.PI / 8);
session.scale(1.1, 1.1);
session.flip('horizontal');
session.resetTransform();
const blob = await session.toBlob({ type: 'image/png' });
const dataUrl = session.toDataUrl('image/png');
console.log(blob, dataUrl); // Blob, 'data:image/png;base64,...'BrowserEnvironment
Browser environment information
Methods
getLocale(): string: get the user's preferred locale.getInformation(config?: BrowserEnvironmentInformationConfig): Promise<BrowserEnvironmentInformation>: get browser environment, hardware, battery, storage, screen, or all information.
Examples
import { BrowserEnvironment } from '@trt-web/browser';
const locale = BrowserEnvironment.getLocale();
const hardware = await BrowserEnvironment.getInformation({ scope: 'hardware' });
const battery = await BrowserEnvironment.getInformation({ scope: 'battery' });
const environment = await BrowserEnvironment.getInformation({ scope: 'environment' });
const screen = await BrowserEnvironment.getInformation({ scope: 'screen' });
const all = await BrowserEnvironment.getInformation(); // 'all' is the default scope
console.log(locale); // 'en'
console.log(hardware); // { hardware: { cores: 8, memoryGB: 16 } }
console.log(battery); // { battery: { charging: true, percent: 50 } }
console.log(environment); // { environment: { locale: 'en-US', preferredLanguages: ['en-US', 'vi-VN'], os: 'macOS', browser: 'Safari', browserVersion: 17, engine: 'WebKit', deviceType: 'desktop' } }
console.log(screen.screenInfo.window); // { innerWidth: 1280, innerHeight: 720, outerHeight: 900, outerWidth: 1440 }
console.log(all.storageHealth); // { ratio: 0.5, quotaGB: 0, persistent: true, risk: 'low' }BrowserFileSystem
File System Access API helpers
Methods
isSupported(): boolean: check whether the File System Access API is supported.openFile(options?: BrowserFileSystemPickerOptions): Promise<BrowserFileSystemFileHandle | BrowserFileSystemFileHandle[] | undefined>: open one or more file handles from the device.readFile(options?: BrowserFileSystemPickerOptions): Promise<BrowserFileSystemReadFileResult | undefined>: open and read one file.readFiles(options?: BrowserFileSystemPickerOptions): Promise<BrowserFileSystemReadFileResult[]>: open and read multiple files.saveFile(data: BlobPart, options?: BrowserFileSystemSavePickerOptions): Promise<boolean>: save data through the file picker.openDirectory(options?: BrowserFileSystemDirectoryPickerOptions): Promise<BrowserFileSystemDirectoryHandle | undefined>: open a directory handle.listDirectory(handle: BrowserFileSystemDirectoryHandle): Promise<BrowserFileSystemEntry[]>: list files and directories from a directory handle.getOpfsRoot(): Promise<FileSystemDirectoryHandle | undefined>: get the origin private file system root.readText(handle: BrowserFileSystemFileHandle): Promise<string | undefined>: read text from an existing file handle.readArrayBuffer(handle: BrowserFileSystemFileHandle): Promise<ArrayBuffer | undefined>: read binary data from an existing file handle.writeText(handle: BrowserFileSystemFileHandle, text: string): Promise<boolean>: replace a file's text contents.appendText(handle: BrowserFileSystemFileHandle, text: string): Promise<boolean>: append text to a file.removeEntry(handle: BrowserFileSystemDirectoryHandle, name: string, options?: { recursive?: boolean }): Promise<boolean>: remove a file or directory entry.requestPermission(handle: BrowserFileSystemPermissionHandle, mode?: BrowserFileSystemPermissionMode): Promise<BrowserFileSystemPermissionState>: query and request access to a file or directory handle.
Examples
import { BrowserFileSystem } from '@trt-web/browser';
const file = await BrowserFileSystem.readFile();
if (file) {
console.log(file.file.name, file.file.size);
}
const fileHandle = await BrowserFileSystem.openFile();
if (fileHandle && !Array.isArray(fileHandle)) {
const binary = await BrowserFileSystem.readArrayBuffer(fileHandle);
const text = await BrowserFileSystem.readText(fileHandle);
console.log(binary?.byteLength, text);
}IndexedDB
IndexedDB database and collection helpers
Methods
isSupported(): boolean: check whether IndexedDB is available in the browser.register(config: IndexedDBDatabaseConfig): IndexedDBDatabase: register a database, its version, and its collections.databases(): Promise<IDBDatabaseInfo[]>: list databases available on the current origin.
Examples
import { IndexedDB } from '@trt-web/browser';
type User = {
id: number;
name: string;
email: string;
};
if (IndexedDB.isSupported()) {
const appDatabase = IndexedDB.register({
database: 'MyAppDB',
version: 1,
collections: ['users'],
});
const users = appDatabase.collection<User>('users');
await users.put({
id: 1,
name: 'Alice',
email: '[email protected]',
});
const user = await users.get(1);
const allUsers = await users.getAll();
console.log(user); // { id: 1, name: 'Alice', email: '[email protected]' }
console.log(allUsers); // [{ id: 1, name: 'Alice', email: '[email protected]' }]
await users.remove(1);
await users.clear();
// The record is removed and the collection is empty after clear().
}BrowserLocation
Geolocation helpers
Methods
getLocation(options?: BrowserLocationOptions): Promise<BrowserLocationResult>: get the current geolocation with permission handling and speed presets.
Examples
import { BrowserLocation } from '@trt-web/browser';
const location = await BrowserLocation.getLocation({ speed: 'fast' });
console.log(location); // { permission: 'granted', data: { coords: { latitude: 5, longitude: 6 } }, success: true }
console.log(await BrowserLocation.getLocation({ speed: 'accurate' })); // { permission: 'granted', data: { coords: { latitude: 3, longitude: 4 } }, success: true }
console.log(await BrowserLocation.getLocation()); // { permission: 'unsupported', success: false } when geolocation is unavailableBrowserMicrophone
Microphone capture and recording
Methods
isSupported(): boolean: check whether microphone capture is supported.listDevices(): Promise<BrowserMicrophoneDevice[]>: list available microphone devices.turnOn(options?: BrowserMicrophoneOptions): Promise<BrowserMicrophoneResult>: request and start a microphone stream.turnOff(): boolean: stop the current microphone stream.createRecorder(options?: BrowserMediaRecorderOptions): Promise<BrowserMediaRecorderSession | undefined>: create an independent recorder session for the microphone stream.
Examples
import { BrowserMicrophone } from '@trt-web/browser';
const audio = document.querySelector<HTMLAudioElement>('#microphone-preview')!;
const result = await BrowserMicrophone.turnOn();
if (result.success) {
audio.srcObject = result.data;
await audio.play();
const recorder = await BrowserMicrophone.createRecorder({ mimeType: 'audio/webm' });
recorder?.pause();
recorder?.resume();
const output = await recorder?.stop();
console.log(output?.blob);
BrowserMicrophone.turnOff();
}BrowserNetwork
Network status and connection information
Methods
isSupported(): boolean: check whether network information is available.getState(): BrowserNetworkState: read online status and connection information.subscribe(handler: (state: BrowserNetworkState) => void): BrowserSubscription: listen for network changes and return a subscription.unsubscribe(): void: unsubscribe all active network subscriptions.
Examples
import { BrowserNetwork } from '@trt-web/browser';
const subscription = BrowserNetwork.subscribe((state) => {
console.log(state.status, state.effectiveType);
});
subscription.unsubscribe();
BrowserNetwork.unsubscribe(); // remove any remaining network subscriptionsBrowserNfc
Web NFC helpers
Methods
isSupported(): boolean: check whether Web NFC is supported.isScanning(): boolean: check whether NFC scanning is active.startScan(options?: BrowserNfcScanOptions): Promise<boolean>: start reading NFC messages.stopScan(): void: stop NFC scanning.write(message: NDEFMessageSource): Promise<boolean>: write an NFC message.
Examples
import { BrowserNfc } from '@trt-web/browser';
if (BrowserNfc.isSupported()) {
await BrowserNfc.startScan({
onReading: (event) => console.log(event.message),
});
await BrowserNfc.write({ records: [{ recordType: 'text', data: 'Hello NFC' }] });
BrowserNfc.stopScan();
}BrowserNotification
Web Notifications API helpers
Methods
isSupported(): boolean: check whether the Notifications API is available in a secure context.getPermission(): Promise<BrowserNotificationPermission>: read the current notification permission.requestPermission(): Promise<BrowserNotificationPermission>: request permission from the user.getMaxActions(): number | undefined: read the maximum number of notification actions supported by the browser.show(title: string, options?: BrowserNotificationOptions): BrowserNotificationSession | undefined: create a notification session when permission is granted.
Examples
import { BrowserNotification } from '@trt-web/browser';
if (BrowserNotification.isSupported()) {
const permission = await BrowserNotification.getPermission();
const nextPermission =
permission === 'prompt' ? await BrowserNotification.requestPermission() : permission;
if (nextPermission === 'granted') {
const notification = BrowserNotification.show('New message', {
body: 'You have a new message.',
icon: '/icons/notification.png',
tag: 'messages',
requireInteraction: true,
data: { messageId: 42 },
});
notification?.addEventListener('show', () => console.log('Notification shown'));
notification?.addEventListener('click', () => console.log('Notification clicked'));
notification?.addEventListener('close', () => console.log('Notification closed'));
notification?.addEventListener('error', () => console.log('Notification failed'));
console.log(notification?.getInfo().content.title); // 'New message'
console.log(notification?.getInfo().content.body); // 'You have a new message.'
console.log(BrowserNotification.getMaxActions()); // number | undefined
notification?.close();
}
}
const progressNotification = BrowserNotification.show('Downloading file', {
body: '45% completed',
tag: 'download-progress',
renotify: true,
icon: '/icons/download.png',
});
console.log(progressNotification?.getInfo().behavior.tag); // 'download-progress'
console.log(progressNotification?.getInfo().behavior.renotify); // true
const callNotification = BrowserNotification.show('Incoming call', {
body: 'Alice is calling you.',
tag: 'call-123',
requireInteraction: true,
icon: '/icons/call.png',
data: { callId: 'call-123' },
});
callNotification?.addEventListener('click', () => {
window.focus();
window.location.assign('/calls/call-123');
});BrowserPeerConnection
WebRTC peer connection helpers
Methods
isSupported(): boolean: check secure-context WebRTC support.isConnected(): boolean: check whether the peer connection is connected.getPeerConnection(): RTCPeerConnection | undefined: Public utility method.createPeerConnection(options?: BrowserPeerConnectionOptions): RTCPeerConnection | undefined: create and configure a peer connection.addTrack(track: MediaStreamTrack, ...streams: MediaStream[]): RTCRtpSender | undefined: add a media track to the peer connection.removeTrack(sender: RTCRtpSender): void: remove a sender from the peer connection.configureVideoSender(options: BrowserPeerConnectionVideoSenderOptions): Promise<boolean>: configure video bitrate and frame rate.createDataChannel(label: string, options?: BrowserPeerConnectionDataChannelInit): RTCDataChannel | undefined: create a data channel.createOffer(options?: RTCOfferOptions): Promise<RTCSessionDescriptionInit | undefined>: create an SDP offer.createAnswer(options?: RTCAnswerOptions): Promise<RTCSessionDescriptionInit | undefined>: create an SDP answer.setLocalDescription(description?: RTCSessionDescriptionInit): Promise<boolean>: set the local SDP description.setRemoteDescription(description: RTCSessionDescriptionInit): Promise<boolean>: set the remote SDP description.addIceCandidate(candidate: RTCIceCandidateInit | null): Promise<boolean>: add a remote ICE candidate.getStats(selector?: MediaStreamTrack | null): Promise<RTCStatsReport | undefined>: read connection statistics.restartIce(): boolean: request an ICE restart.createConnectionFromOffer(offer: RTCSessionDescriptionInit, options?: BrowserPeerConnectionOptions): Promise<RTCPeerConnection | undefined>: create a connection and apply a remote offer.close(): void: close the peer connection and remove listeners.
Examples
import { BrowserPeerConnection } from '@trt-web/browser';
BrowserPeerConnection.createPeerConnection({
config: { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] },
handlers: { onIceCandidate: (event) => console.log(event.candidate) },
});
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
const sender = BrowserPeerConnection.addTrack(stream.getVideoTracks()[0], stream);
await BrowserPeerConnection.configureVideoSender({
maxBitrate: 1_000_000,
maxFramerate: 30,
});
if (sender) {
BrowserPeerConnection.removeTrack(sender);
}
const offer = await BrowserPeerConnection.createOffer();
await BrowserPeerConnection.setLocalDescription(offer);
BrowserPeerConnection.close();
if (offer) {
const connection = await BrowserPeerConnection.createConnectionFromOffer(offer, {
handlers: { onIceCandidate: (event) => console.log(event.candidate) },
});
connection?.close();
}BrowserPerformance
Performance API helpers
Methods
isSupported(): boolean: check whether the Performance API is available.createSession(): BrowserPerformanceSession | undefined: create a session exposing the native Performance properties and methods.now(): number | undefined: Public utility method.mark(name: string): boolean: Public utility method.measure(name: string, startMark?: string, endMark?: string): PerformanceMeasure | undefined: Public utility method.measureAsync<T>(name: string, callback: () => Promise<T>): Promise<{ value: T; measure: PerformanceMeasure } | undefined>: Public utility method.getEntries(options?: BrowserPerformanceEntriesOptions): PerformanceEntry[]: Public utility method.getNavigationTiming(): BrowserPerformanceNavigationTiming | undefined: Public utility method.getResourceTiming(): PerformanceResourceTiming[]: Public utility method.clearMarks(name?: string): void: Public utility method.clearMeasures(name?: string): void: Public utility method.analyzePage(): BrowserPerformancePageAnalysis | undefined: return a normalized snapshot of current page navigation, resources, memory, and interaction data.
Examples
import { BrowserPerformance } from '@trt-web/browser';
const result = await BrowserPerformance.measureAsync('load-users', async () => {
await new Promise((resolve) => setTimeout(resolve, 100));
return [{ id: 1, name: 'Alice' }];
});
console.log(result?.value, result?.measure.duration);
// Output: [{ id: 1, name: 'Alice' }] 42.5
const performance = BrowserPerformance.createSession();
console.log(performance?.timeOrigin);
console.log(performance?.getEntriesByType('resource'));
console.log(await performance?.measureUserAgentSpecificMemory());BrowserPermission
Browser permission helpers
Methods
supportedPermissions(): BrowserPermissionName[]: list permissions supported by the utility.getState(name: BrowserPermissionName): Promise<BrowserPermissionState>: check the state of a browser permission.request(name: BrowserPermissionName): Promise<BrowserPermissionState>: request a browser permission.
Examples
import { BrowserPermission } from '@trt-web/browser';
const current = await BrowserPermission.getState('geolocation');
console.log(BrowserPermission.supportedPermissions()); // ['geolocation', 'notifications', ...]
const requested = current === 'prompt' ? await BrowserPermission.request('geolocation') : current;
console.log(current); // 'granted' | 'denied' | 'prompt' | 'unsupported'
console.log(requested); // 'granted' when permission is granted
console.log(await BrowserPermission.request('notifications')); // 'prompt' when the browser returns 'default'
console.log(await BrowserPermission.request('geolocation')); // 'denied' when the user rejects accessBrowserPresentation
Fullscreen and picture-in-picture helpers
Methods
enterFullscreen(element?: Element): Promise<boolean>: enter fullscreen mode for an element.exitFullscreen(): Promise<boolean>: exit fullscreen mode.enterPictureInPicture(video: HTMLVideoElement): Promise<boolean>: enter picture-in-picture mode for a video.exitPictureInPicture(): Promise<boolean>: exit picture-in-picture mode.
Examples
import { BrowserPresentation } from '@trt-web/browser';
const element = document.querySelector<HTMLElement>('#preview');
const video = document.querySelector<HTMLVideoElement>('#video-preview');
const entered = await BrowserPresentation.enterFullscreen(element ?? undefined);
const exited = await BrowserPresentation.exitFullscreen();
console.log({ entered, exited }); // { entered: true, exited: true }
console.log(await BrowserPresentation.enterFullscreen()); // false when fullscreen is unsupported
if (video) {
console.log(await BrowserPresentation.enterPictureInPicture(video)); // true
}
console.log(await BrowserPresentation.exitPictureInPicture()); // trueBrowserResource
Browser resource loading and download helpers
Methods
assetUrl(path: string): string: resolve an asset path against the document base URL.isCached(url: string, options?: BrowserResourceCacheOptions): Promise<boolean>: check whether a browser resource is cached.loadScript(src: string): Promise<HTMLScriptElement>: load a script once and reuse concurrent requests.loadLink(href: string): Promise<HTMLLinkElement>: load a stylesheet once and reuse concurrent requests.download(src: string | Blob | File, config?: BrowserResourceDownloadConfig): Promise<void>: download a URL, Blob, or File in the current tab, or open it in a new tab.
Examples
import { BrowserResource } from '@trt-web/browser';
await BrowserResource.loadScript('/assets/analytics.js');
await BrowserResource.loadLink('/assets/theme.css');
const cached = await BrowserResource.isCached('/assets/theme.css');
await BrowserResource.download('/exports/report.pdf', {
name: 'monthly-report',
ext: 'pdf',
target: '_self',
maxBlobSize: { value: 50, unit: 'Mb' },
});
console.log({ cached }); // { cached: true } when the resource is found in Cache Storage or has a zero transfer size
console.log(BrowserResource.assetUrl('assets/theme.css')); // 'https://example.com/app/assets/theme.css'
// For a URL with target '_self', HEAD checks Content-Length first.
// Small files are fetched as Blob; unknown or large files open in '_blank'.
await BrowserResource.download('/exports/report.pdf', {
target: '_blank',
}); // opens the URL in a new tab; it does not force a download
const preview = new Blob(['Preview content'], { type: 'text/plain' });
await BrowserResource.download(preview, {
target: '_blank',
}); // opens the Blob in a new tabBrowserScreen
Screen sharing and recording
Methods
isSupported(): boolean: check whether screen capture is supported.startShare(options?: BrowserScreenStreamConstraints): Promise<MediaStream>: start screen or window sharing.stopShare(): boolean: stop the current screen-sharing stream.screenshot(config?: BrowserScreenScreenshotConfig): Promise<Blob | undefined>: capture a frame from the shared screen.createRecorder(options?: BrowserMediaRecorderOptions): Promise<BrowserMediaRecorderSession | undefined>: create an independent recorder session for the shared screen.
Examples
import { BrowserScreen } from '@trt-web/browser';
const screenshot = await BrowserScreen.screenshot({
image: { type: 'image/png' },
});
console.log(screenshot?.size);
const video = document.querySelector<HTMLVideoElement>('#screen-preview')!;
const stream = await BrowserScreen.startShare();
if (stream) {
video.srcObject = stream;
const recorder = await BrowserScreen.createRecorder({ mimeType: 'video/webm' });
recorder?.pause();
recorder?.resume();
const output = await recorder?.stop();
console.log(output?.blob);
BrowserScreen.stopShare();
}BrowserSpeechToText
Speech recognition helpers
Methods
isSupported(): boolean: check whether Speech Recognition is supported.recognize(options?: BrowserSpeechToTextOptions): Promise<string | undefined>: recognize speech using the configured language.
Examples
import { BrowserSpeechToText } from '@trt-web/browser';
if (BrowserSpeechToText.isSupported()) {
// Start recognition from a user gesture, such as a button click.
const text = await BrowserSpeechToText.recognize({
lang: 'en-US',
interimResults: true,
});
console.log(text);
}BrowserTextToSpeech
Speech synthesis helpers
Methods
isSupported(): boolean: check whether Speech Synthesis is supported.speak(text: string, options?: BrowserTextToSpeechOptions): Promise<void>: speak text using the selected voice and options.getVoices(): Promise<SpeechSynthesisVoice[]>: list available speech synthesis voices.pause(): void: pause current speech.resume(): void: resume paused speech.cancel(): void: cancel current speech.isSpeaking(): boolean: check whether speech is active.isPaused(): boolean: check whether speech is paused.
Examples
import { BrowserTextToSpeech } from '@trt-web/browser';
if (BrowserTextToSpeech.isSupported()) {
await BrowserTextToSpeech.speak('Hello from the browser', { lang: 'en-US' });
console.log(BrowserTextToSpeech.isSpeaking());
}BrowserTabActivity
Tab visibility and focus helpers
Methods
isSupported(): boolean: check whether tab activity tracking is supported.getState(): BrowserTabActivityState: read the current focus and visibility state.subscribe(handler: (state: BrowserTabActivityState) => void): BrowserSubscription: listen for tab activity changes and return a subscription.unsubscribe(): void: remove the associated browser event listeners.
Examples
import { BrowserTabActivity } from '@trt-web/browser';
const subscription = BrowserTabActivity.subscribe((state) => {
console.log(state);
});
subscription.unsubscribe();
BrowserTabActivity.unsubscribe(); // remove any remaining tab subscriptionsBrowserTheme
System theme observation
Methods
isSupported(): boolean: check whether system theme observation is supported.getSystemTheme(): BrowserThemeMode: read the systemdarkorlighttheme.subscribe(handler: (theme: BrowserThemeMode) => void): BrowserSubscription: listen for system theme changes and return a subscription.
Examples
import { BrowserTheme } from '@trt-web/browser';
const applyTheme = (theme: 'dark' | 'light') => {
document.documentElement.dataset['theme'] = theme;
};
applyTheme(BrowserTheme.getSystemTheme());
const subscription = BrowserTheme.subscribe((theme) => {
applyTheme(theme);
});
subscription.unsubscribe();BrowserVibration
Vibration API helpers
Methods
isSupported(): boolean: check whether the Vibration API is supported.vibrate(pattern: BrowserVibratePattern): boolean: start a vibration pattern on the device.cancel(): boolean: cancel the current vibration.
Examples
import { BrowserVibration } from '@trt-web/browser';
if (BrowserVibration.isSupported()) {
BrowserVibration.vibrate([200, 100, 200]);
BrowserVibration.cancel();
}BrowserViewport
Responsive viewport state helpers
Methods
register(config: BrowserViewportConfig): void: replace the global viewport range configuration.getCurrentState(): BrowserViewportState: read the current viewport size, orientation, and all matching ranges.isInRange(range: BrowserViewportRangeName): boolean: check whether a named range currently matches.subscribe(handler: (state: BrowserViewportState) => void): BrowserSubscription: listen to resize changes with an independent subscription.
Examples
import { BrowserViewport } from '@trt-web/browser';
BrowserViewport.register({
phone: { max: 599 },
tablet: { min: 600, max: 1023 },
desktop: { min: 1024 },
wide: { min: 1440 },
});
console.log(BrowserViewport.getCurrentState());
// {
// width: 1440,
// height: 900,
// orientation: 'landscape',
// ranges: ['desktop', 'wide'],
// }
// Receive every viewport resize update.
const allSubscription = BrowserViewport.subscribe((state) => {
console.log(state.width, state.height, state.ranges);
});
// Receive updates only while the viewport matches the tablet range.
const tabletSubscription = BrowserViewport.subscribe(
(state) => {
console.log('Tablet viewport:', state.width, state.height);
},
{ range: 'tablet' },
);
console.log(BrowserViewport.isInRange('tablet')); // false
allSubscription.unsubscribe();
tabletSubscription.unsubscribe();BrowserWakeLock
Screen wake lock helpers
Methods
isSupported(): boolean: check whether the Screen Wake Lock API is supported.isActive(): boolean: check whether a screen wake lock is active.enable(): Promise<boolean>: request a screen wake lock.disable(): Promise<void>: release the active screen wake lock.
Examples
import { BrowserWakeLock } from '@trt-web/browser';
if (BrowserWakeLock.isSupported()) {
const enabled = await BrowserWakeLock.enable();
console.log(enabled, BrowserWakeLock.isActive());
await BrowserWakeLock.disable();
}BrowserWindow
Current window helpers
Methods
reload(): void: reload the current tab.goBack(): void: navigate backward in the current tab.goForward(): void: navigate forward in the current tab.pushState(data: unknown, unused: string, url?: string | URL): void: add a history entry without reloading the page.replaceState(data: unknown, unused: string, url?: string | URL): void: replace the current history entry without reloading the page.historyState(): unknown: read the current history state.alert(message: string): void: show a browser alert dialog.confirm(message: string): boolean: show a browser confirmation dialog.prompt(title: string, defaultValue?: string): string | null: show a browser prompt dialog.print(): void: open the browser print dialog.preload(url: string, options?: BrowserWindowPreloadOptions): HTMLLinkElement | undefined: preload a URL resource.getKeyboardEventInfo(event: KeyboardEvent): BrowserKeyboardEventInfo: extract keyboard event information.getPointerEventInfo(event: PointerEvent): BrowserPointerEventInfo: extract pointer event information.
Examples
import { BrowserWindow } from '@trt-web/browser';
BrowserWindow.preload('/assets/app.js');
BrowserWindow.pushState({ section: 'settings' }, '', '/settings');
BrowserWindow.replaceState({ section: 'profile' }, '', '/profile');
console.log(BrowserWindow.historyState());
const confirmed = BrowserWindow.confirm('Continue?');
if (confirmed) {
BrowserWindow.print();
}
// Call reload when the current page should be loaded again.
// BrowserWindow.reload();BrowserShare
Web Share API helpers
Methods
share(data: BrowserShareData): Promise<ExecuteBrowserServiceResult>: share content through the browser's native share sheet when supported.
Examples
import { BrowserShare } from '@trt-web/browser';
const result = await BrowserShare.share({
title: 'Monthly report',
text: 'The report is ready.',
url: 'https://example.com/report',
});
console.log(result);
/**
* {
* permission: 'granted',
* data: {
* title: 'Monthly report',
* text: 'The report is ready.',
* url: 'https://example.com/report'
* },
* success: true
* } */BrowserWindowManager
Child window lifecycle helpers
Methods
open(config?: BrowserWindowOpenConfig): BrowserWindowInstance | null: open a child browser window and return an instance for closing the window or listening to its lifecycle changes.
Examples
import { BrowserWindowManager } from '@trt-web/browser';
const child = BrowserWindowManager.open({
url: '/preview',
target: 'preview-window',
features: 'width=800,height=600,resizable=yes',
title: 'Preview',
pollInterval: 250,
});
if (!child) {
console.log('The browser blocked the popup.');
} else {
child.onFocus = () => {
console.log('Preview focused.');
};
child.onBlur = () => {
console.log('Preview lost focus.');
};
child.onResize = ({ width, height }) => {
console.log('Preview resized:', width, height);
};
child.onZoomChange = ({ devicePixelRatio, direction }) => {
console.log('Preview zoom changed:', direction, devicePixelRatio);
};
child.onClose = () => {
console.log('Preview closed.');
};
child.close();
}Cookie
Cookie storage helpers
Methods
isSupported(): boolean: check whether cookies are supported and enabled.set<T>(name: string, value: T, config?: CookieSetConfig): void: store typed data in a cookie.get<T>(name: string): T | undefined: read typed data from a cookie.remove(name: string, config?: CookieSetConfig): void: remove a cookie.clear(): void: remove all accessible cookies.exists(name: string): boolean: check whether a cookie exists.
Examples
import { Cookie } from '@trt-web/browser';
Cookie.set('preferences', { theme: 'dark' }, { expiresIn: 7 });
const preferences = Cookie.get<{ theme: string }>('preferences');
console.log(preferences, Cookie.exists('preferences')); // { theme: 'dark' } true
Cookie.set('session', { active: true }, { expiresIn: { value: 1, unit: 'hour' } });
console.log(Cookie.get('session')); // { active: true }
Cookie.remove('preferences');
Cookie.clear();
console.log(Cookie.get('session')); // undefinedLocalStorage
Local storage helpers
Methods
isSupported(): boolean: check whetherlocalStorageis supported and available.set<T>(key: string, value: T): void: store typed data inlocalStorage.get<T>(key: string): T | undefined: read typed data fromlocalStorage.remove(key: string): void: remove an item fromlocalStorage.clear(): void: remove all items fromlocalStorage.exists(key: string): boolean: check whether a key exists inlocalStorage.
Examples
import { LocalStorage } from '@trt-web/browser';
LocalStorage.set('profile', { id: 1, name: 'Alice' });
const profile = LocalStorage.get<{ id: number; name: string }>('profile');
console.log(profile, LocalStorage.exists('profile')); // { id: 1, name: 'Alice' } true
LocalStorage.remove('profile');
console.log(LocalStorage.get('profile')); // undefined
LocalStorage.clear();SessionStorage
Session storage helpers
Methods
isSupported(): boolean: check whethersessionStorageis supported and available.set<T>(key: string, value: T): void: store typed data insessionStorage.get<T>(key: string): T | undefined: read typed data fromsessionStorage.remove(key: string): void: remove an item fromsessionStorage.clear(): void: remove all items fromsessionStorage.exists(key: string): boolean: check whether a key exists insessionStorage.
Examples
import { SessionStorage } from '@trt-web/browser';
SessionStorage.set('draft', { title: 'Untitled' });
console.log(SessionStorage.get('draft')); // { title: 'Untitled' }
console.log(SessionStorage.exists('draft')); // true
SessionStorage.remove('draft');
console.log(SessionStorage.get('draft')); // undefined
SessionStorage.clear();