connect.capabilities
Introspect and request the extension's own permissions — list, contains, request.
Introspect and request the extension's own permissions. No capability — an extension can always see what it has and ask for more (within what its manifest declares). This is how you feature-detect before using a gated API, and how you request a declared capability at runtime without a reload.
- Capability: none
- Namespace:
connect.capabilities
See Capabilities & consent for the permission model.
Walkthrough
Use a gated API only if it's allowed, and ask if it isn't.
- Feature-detect with
containsbefore calling a gated API. - Request a declared-but-ungranted capability when the user opts into a feature.
- Re-arm any gated event subscriptions from
runtime.onGrantsChangedafter a grant.
// 1 — branch on what's granted (no error on the "not granted" path)
if (await connect.capabilities.contains('history.read')) render(await connect.history.list());
// 2 — ask for more when the user turns a feature on
const { granted } = await connect.capabilities.request(['history.read']);
if (granted.includes('history.read')) render(await connect.history.list());Methods
capabilities.list()
What this extension has and asked for, in the current profile.
How to use it
- Call it to read
{ requested, granted, profileId }— useful for a settings screen.
Signature — connect.capabilities.list() · Returns — Promise<{ requested, granted, profileId }>.
capabilities.contains(cap)
Is a capability currently granted? The right check to run before code that needs a permission the user may not have allowed.
How to use it
- Pass a token (
'history.read'), a{ host: url }check, or an array (all-of). - Branch on the
boolean; skip the gated path if it's false.
Signature — connect.capabilities.contains(cap)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
cap | string | one form | A coarse token, e.g. 'history.read'. |
cap | { host: url } | one form | True if a granted host pattern covers url. |
cap | array | one form | True only if all listed capabilities are granted. |
Returns — Promise<boolean>.
if (await connect.capabilities.contains('history.read')) {
render(await connect.history.list()); // allowed
} // else: run without history — no error thrown
if (await connect.capabilities.contains({ host: tab.url })) { /* inject */ }
if (await connect.capabilities.contains(['cookies', { host: url }])) { /* … */ }capabilities.request(capabilities)
Prompt the user for manifest-declared capabilities not yet granted — no reload needed.
How to use it
- Call it in response to a user action (opening a feature), not on load.
- Read
{ granted }and proceed only if what you need is in it.
Signature — connect.capabilities.request(capabilities)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
capabilities | string[] | object[] | yes | The declared capabilities to request. |
Returns — Promise<{ granted }>.
Errors & edge cases
- Already-granted → resolves immediately.
- Undeclared capabilities → denied (no escalation — you can only request what your manifest declares).
- A 120s timeout → not granted.
const { granted } = await connect.capabilities.request(['history.read']);
if (granted.includes('history.read')) render(await connect.history.list());Notes
- Prefer
contains(branch and skip) over calling a gated API and catchingCAPABILITY_DENIED— it avoids a thrown error on the expected "not granted" path. - Re-arm gated event subscriptions from
runtime.onGrantsChangedafter a grant lands.