Implementation:Puppeteer Puppeteer Decorators
| Property | Value |
|---|---|
| sources | packages/puppeteer-core/src/util/decorators.ts |
| domains | Utility, Decorators, Metaprogramming |
| last_updated | 2026-02-12 00:00 GMT |
Overview
Description
The decorators module provides a collection of TypeScript decorators used throughout Puppeteer to add cross-cutting behavior to classes and methods. These decorators implement patterns for resource lifecycle management, concurrency control, memoization, and event propagation.
The module exports six decorators:
- moveable -- A class decorator that enables move semantics on disposable objects. When an object is "moved", its dispose/asyncDispose methods become no-ops for the original reference, allowing ownership transfer without triggering disposal.
- throwIfDisposed -- A method decorator factory that throws an error if the method is called on a disposed object (one where
this.disposedis true). - inertIfDisposed -- A method decorator that silently returns without executing if the object is disposed, rather than throwing.
- invokeAtMostOnceForArguments -- A method decorator that memoizes calls based on arguments using nested WeakMap chains. If the same combination of object arguments has been seen before, the method is skipped.
- guarded -- A method decorator factory that serializes concurrent calls to an async method using a per-instance Mutex. Concurrent calls are queued and executed one at a time.
- bubble -- An accessor decorator factory for EventEmitter fields. Events emitted by the decorated field are automatically re-emitted ("bubbled") on the owning object. An optional event type filter can restrict which events are bubbled.
Usage
These decorators are applied throughout Puppeteer's internal classes. For example, throwIfDisposed guards methods on Page and Browser objects, guarded serializes write operations on ScreenRecorder, and bubble propagates events from child emitters to parent objects.
Code Reference
Source Location
packages/puppeteer-core/src/util/decorators.ts
Signature
export function moveable<
Class extends abstract new (...args: never[]) => Moveable,
>(Class: Class, _: ClassDecoratorContext<Class>): Class;
export function throwIfDisposed<This extends Disposed>(
message?: (value: This) => string,
): (target: (this: This, ...args: any[]) => any, _: unknown) => typeof target;
export function inertIfDisposed<This extends Disposed>(
target: (this: This, ...args: any[]) => any,
_: unknown,
): typeof target;
export function invokeAtMostOnceForArguments(
target: (this: unknown, ...args: any[]) => any,
_: unknown,
): typeof target;
export function guarded<T extends object>(
getKey?: (this: T) => object,
): (
target: (this: T, ...args: any[]) => Promise<any>,
_: ClassMethodDecoratorContext<T>,
) => typeof target;
export function bubble<T extends EventType[]>(
events?: T,
): ClassAccessorDecoratorResult<EventEmitter, EventEmitter>;
Import
import {moveable, throwIfDisposed, inertIfDisposed, invokeAtMostOnceForArguments, guarded, bubble} from '../util/decorators.js';
I/O Contract
| Decorator | Parameter | Type | Description |
|---|---|---|---|
| throwIfDisposed | message | (value: This) => string |
Optional function to generate a custom error message |
| guarded | getKey | (this: T) => object |
Optional function returning the key object for the mutex; defaults to this
|
| bubble | events | EventType[] |
Optional list of event types to bubble; if omitted, all events bubble |
| Decorator | Behavior |
|---|---|
| moveable | Enables move semantics for disposable class instances |
| throwIfDisposed | Throws error when method called on disposed instance |
| inertIfDisposed | Silently returns when method called on disposed instance |
| invokeAtMostOnceForArguments | Skips invocation if same arguments have been seen before |
| guarded | Serializes concurrent async method calls via a mutex |
| bubble | Re-emits events from decorated accessor field on the owning emitter |
Usage Examples
// Guard a method so it throws when the object is disposed
class MyPage {
disposed = false;
@throwIfDisposed()
async navigate(url: string) {
// ...
}
}
// Serialize concurrent calls to an async method
class ScreenRecorder {
@guarded()
async writeFrame(buffer: Buffer) {
await this.process.stdin.write(buffer);
}
}
// Bubble events from a child emitter to the parent
class BrowserContext extends EventEmitter {
@bubble()
accessor page: PageEmitter;
}