Skip to main content

api.storage

Interface: IStorageApi

Implementation tier: T1 (KV, secrets, settings) / T2 (openDatabase)

Key-value storage, OS keychain secrets, read-only settings mirror, and per-extension SQLite databases.

Permissions

  • storage
  • storage:secrets (for secret methods)
  • storage:database (for openDatabase)
info

Backed by the extension_storage SQLite table. The host auto-prefixes the extension ID; extensions cannot read each other's keys.

Quotas:

  • KV tier: default 5 MB per extension. Exceeding throws QuotaExceededError. Configurable in Preferences.
  • Database tier: no hard quota by default — extensions that opt in via storage:database are expected to need real space (indexes, embeddings, custom corpora). The Extensions UI shows per-extension disk usage and lets the user set a per-extension cap if desired.
  • Secrets: no quota; OS keychain limits apply.

Methods

get

get<T = unknown>(key: string): Promise<T | undefined>

Parameters:

NameTypeRequiredDescription
keystringYes

Returns: Promise<T | undefined>


set

set(key: string, value: unknown): Promise<void>

Parameters:

NameTypeRequiredDescription
keystringYes
valueunknownYes

Returns: Promise<void>


delete

delete(key: string): Promise<void>

Parameters:

NameTypeRequiredDescription
keystringYes

Returns: Promise<void>


keys

keys(): Promise<string[]>

Returns: Promise<string[]>


setSecret

setSecret(key: string, value: string): Promise<void>

Routes through the OS keychain (keytar) for sensitive values.

Parameters:

NameTypeRequiredDescription
keystringYes
valuestringYes

Returns: Promise<void>


getSecret

getSecret(key: string): Promise<string | undefined>

Parameters:

NameTypeRequiredDescription
keystringYes

Returns: Promise<string | undefined>


deleteSecret

deleteSecret(key: string): Promise<void>

Parameters:

NameTypeRequiredDescription
keystringYes

Returns: Promise<void>


getSetting

getSetting<T = unknown>(key: string): Promise<T | undefined>

Read a user-edited setting defined in contributes.configuration. The host populates these from the rendered settings form. Equivalent to get('__settings.<key>') but type-safe against the schema.

Parameters:

NameTypeRequiredDescription
keystringYes

Returns: Promise<T | undefined>


openDatabase

openDatabase(name: string, opts?: OpenDatabaseOpts): Promise<IExtensionDatabase>

Open a SQLite database file owned by this extension. The file lives at data/extensions/<id>/db/<name>.db. Use this for indexes, embeddings, or any data that exceeds the KV tier. Requires the storage:database permission. The host opens the file with WAL mode and foreign keys on.

The database is created on first open. The host runs no migrations — the extension is responsible for its own schema. The host backs the file up with the rest of user data unless the extension marks it ephemeral via opts.

Parameters:

NameTypeRequiredDescription
namestringYes
optsOpenDatabaseOptsNo

Returns: Promise<IExtensionDatabase>


diskUsage

diskUsage(): Promise<{ kv: number; databases: number; secretsCount: number }>

Approximate disk usage of all storage owned by this extension, in bytes.

Returns: Promise<{ kv: number; databases: number; secretsCount: number }>


requestFolder

requestFolder(purpose: string): Promise<FolderGrantHandle | null>

Request a user-chosen folder for scoped file storage. The host opens a folder picker dialog; if the user selects a folder the grant is persisted so it survives extension restarts. Returns null if the user cancelled. Requires the fs:managed-folder permission.

@param purpose - Human-readable reason shown in the folder picker dialog.

Parameters:

NameTypeRequiredDescription
purposestringYes- Human-readable reason shown in the folder picker dialog.

Returns: Promise<FolderGrantHandle | null>


getFolderGrant

getFolderGrant(): Promise<FolderGrantHandle | null>

Get the current folder grant, if one exists. Returns null if no grant has been made or if it was revoked. Requires fs:managed-folder.

Returns: Promise<FolderGrantHandle | null>


revokeFolderGrant

revokeFolderGrant(): Promise<void>

Revoke the current folder grant. The files on disk are NOT deleted — only the extension's access is removed. Requires fs:managed-folder.

Returns: Promise<void>


readFile

readFile(path: string): Promise<ArrayBuffer>

Read a file inside the granted folder. The path is relative to the grant root and must not escape it. Requires fs:managed-folder.

Parameters:

NameTypeRequiredDescription
pathstringYes

Returns: Promise<ArrayBuffer>


writeFile

writeFile(path: string, data: ArrayBuffer | Uint8Array): Promise<void>

Write (or overwrite) a file inside the granted folder. The path is relative to the grant root. Parent directories are created automatically. Requires fs:managed-folder.

Parameters:

NameTypeRequiredDescription
pathstringYes
dataArrayBuffer | Uint8ArrayYes

Returns: Promise<void>


deleteFile

deleteFile(path: string): Promise<void>

Delete a file inside the granted folder. No-op if the file does not exist. Requires fs:managed-folder.

Parameters:

NameTypeRequiredDescription
pathstringYes

Returns: Promise<void>


listFiles

listFiles(prefix?: string): Promise<FileInfo[]>

List files and directories inside the granted folder, optionally filtered by a relative path prefix. Requires fs:managed-folder.

Parameters:

NameTypeRequiredDescription
prefixstringNo

Returns: Promise<FileInfo[]>


statFile

statFile(path: string): Promise<FileInfo | null>

Get metadata for a single file inside the granted folder. Returns null if the file does not exist. Requires fs:managed-folder.

Parameters:

NameTypeRequiredDescription
pathstringYes

Returns: Promise<FileInfo | null>


getFolderUsage

getFolderUsage(): Promise<FolderUsageInfo>

Get aggregate disk usage for the granted folder. Requires fs:managed-folder.

Returns: Promise<FolderUsageInfo>


Events

onDidChangeSettings

onDidChangeSettings: IEventApi<{ keys: string[] }>

Payload type: { keys: string[] }

Subscribe to this event:

const handle = await api.storage.onDidChangeSettings.subscribe((payload) => {
// Handle event
});

// Later, to unsubscribe:
await handle.dispose();