Start with the contract. src/definitions.ts is the API every platform must honor, and its JSDoc comments become the README's API reference when the build runs docgen:
export interface SpaceInfo {
/** Bytes the app can still write on the volume that holds its files. */
freeBytes: number;
/** Size of that volume in bytes. */
totalBytes: number;
}
export interface DiskSpacePlugin {
/** Free and total space where the app keeps its files. */
getSpace(): Promise<SpaceInfo>;
/** Whether a download of `bytes` would fit right now. */
canFit(options: { bytes: number }): Promise<{ fits: boolean; freeBytes: number }>;
}Each method takes one options object at most and returns a promise of an object, which survives the JSON round trip of Serializing Across the Bridge. The generated src/index.ts needs no edits: it calls registerPlugin<DiskSpacePlugin>('DiskSpace', { web: ... }), importing the web class only in a browser. That class is a real fallback, built on the StorageManager API:
export class DiskSpaceWeb extends WebPlugin implements DiskSpacePlugin {
async getSpace(): Promise<SpaceInfo> {
if (!navigator.storage?.estimate) {
throw this.unavailable('The StorageManager API is not available in this browser.');
}
const { quota = 0, usage = 0 } = await navigator.storage.estimate();
return { freeBytes: quota - usage, totalBytes: quota };
}
async canFit(options: { bytes: number }): Promise<{ fits: boolean; freeBytes: number }> {
const { freeBytes } = await this.getSpace();
return { fits: options.bytes <= freeBytes, freeBytes };
}
}The unavailable() and unimplemented() helpers of WebPlugin build a CapacitorException with the same codes the native side uses. npm 2,036 run build chains docgen, tsc and Rollup 141,981 into dist/, with ES modules for Vite 25,978 plus CommonJS and script-tag bundles.