events.subscribe / events.unsubscribe and the ‘event’ notification.
notifications
island.notify and the ‘notification.action’ notification.
storage
storage.get / set / delete / keys.
secrets
secrets.get / set / delete.
views
contributes.views drawn on the island; view.update / view.patch and the view.action / view.submit / view.search / view.visible notifications.
status
contributes.statusItems on the collapsed bar; status.update.
webview
contributes.views with template ‘webview’ (the plugin’s own HTML page); webview.postMessage and the ‘webview.message’ notification.
permissions
manifest optionalPermissions and permissions.request; initialize.optionalPermissions.
openView
island.openView: a plugin opens its own page right after the user used it.
statusCells
status.update draws ‘cells’ (label-over-value columns) and a ‘ring’ (0-1). Islands without it ignore both and show the text.
notifyStyle
island.notify takes ‘icon’ (‘media’: the icon of the app playing media) and ‘layout’ (‘inline’: alone in the new-messages popup, the island is the message, with no title row or card). Islands without it ignore both.
notifyControls
island.notify takes ‘controls’ (‘media’: the island draws previous, play / pause and next beside the message and runs them itself; the plugin needs no media:control). Islands without it ignore it.
statusBatteries
status.update draws ‘batteries’ (upright batteries, each 0-1 full). Islands without it ignore them and show the text or cells.
结果:Every declared setting with its current value (defaults filled in).
settings.set
权限:不需要
参数:
values:{ key: value }: settings from the manifest’s contributes.settings, each of its declared type
结果:{ settings }: every setting afterwards. All or none: an unknown key or a wrong type is status 400 and changes nothing. The settings page shows the new values; the plugin gets no settings.changed for its own change.
reason:string (1-100 chars) shown on the plugin page; null lets the plugin stop when idle again
结果:{}. Only matters for on-demand plugins (activationEvents), which otherwise stop after 60 s with nothing to do.
权限
permissions.request
权限:不需要
参数:
permissions:[name]: 1-14 names from the manifest’s optionalPermissions (or permissions)
结果:{ granted: [name], denied: [name] }. The island asks the user about each optional permission not answered yet (allow, allow once, deny; at most 30 s each, no answer is a denial that is asked again next time). A remembered deny is not asked again until the user revokes it in the plugin’s settings. A name the manifest does not list is status 400.
事件订阅
events.subscribe
权限:不需要
参数:
events:[string] (max 16; each needs the event’s permission; all are checked before any is applied)
结果:{ events }: every event the plugin is subscribed to, sorted
events.unsubscribe
权限:不需要
参数:
events:[string] (max 16)
结果:{ events }
岛上界面
view.update
权限:不需要
参数:
viewId:one of the plugin’s contributes.views
model:object for the view’s template (see docs/plugins/README.md); max 256 KB as JSON, else status 413
结果:{}. The island shows at most 10 changes a second per view (later ones are merged) and only while the page is on screen.
webview.postMessage
权限:不需要
参数:
viewId:one of the plugin’s views with template webview
message:any JSON value; max 256 KB
结果:{ shown }: false when the page is not on screen (the message is dropped). Messages sent before the page’s script runs are lost too, so wait for the page to post that it is ready.
view.patch
权限:不需要
参数:
viewId:string
items?:[{ id, … }]: replace the items with these ids in model.items and model.groups[].items
remove?:[id]: delete the items with these ids
add?:[{ item: { id, … }, before?: id, group?: number }]: insert before the item before, else at the end of model.groups[group].items, else at the end of model.items; an id already in the view is status 400
结果:{ missing: [id] }: ids not found (an add whose before is missing goes at the end). At least one of items, remove and add. Status 409 before the first view.update.
status.update
权限:不需要
参数:
itemId:one of the plugin’s contributes.statusItems
text:string, max 24 characters; empty clears the item
tooltip?:string, max 200
tone?:neutral | accent | warning | danger
cells?:[{ label: string max 6, value: string max 8, tone?: as above }], at most 4; drawn instead of the text (capability statusCells)
ring?:number 0-1: a small progress ring in the item’s tone before the text or cells (capability statusCells)
batteries?:[{ level: number 0-1, tone?: as above }], at most 4 upright batteries drawn instead of the text and cells; one without a tone takes its place’s color (capability statusBatteries)
结果:{}
island.openView
权限:不需要
能力:openView
参数:
viewId:one of the plugin’s contributes.views
结果:{}. Shows the island and opens that page. Only within 15 s of the user using the plugin (a command or its shortcut, an island.notify button, a focusd:// link, an action, form or webview message on one of its pages), else status 403; a view the plugin does not declare is status 404.
island.notify
权限:island:notify
参数:
title:string (1-80 chars)
body?:string (max 200)
durationMs?:number, clamped to 2000-15000, default 5000
icon?:‘plugin’ (default) | ‘media’: the icon of the app playing media, else the plugin’s (capability notifyStyle)
layout?:‘card’ (default) | ‘inline’: alone in the new-messages popup, no title row or card (capability notifyStyle)
controls?:‘none’ (default) | ‘media’: previous, play / pause and next beside the message, run by the island (capability notifyControls)
结果:{ muted }: true when the user turned this plugin’s messages off (nothing is shown). At most 6 per minute per plugin, else -32000 with status 429.
插件自己的数据
storage.get
权限:不需要
参数:
key:string (1-128 chars)
结果:{ value }: null when the key is not set
storage.set
权限:不需要
参数:
key:string (1-128 chars)
value:any JSON (max 64 KB as JSON; the plugin’s whole storage max 1 MB, else status 413)
结果:{}
storage.delete
权限:不需要
参数:
key:string
结果:{ deleted }
storage.keys
权限:不需要
参数:无
结果:{ keys }
secrets.get
权限:secrets
参数:
key:letters, digits, ’.’, ’_’, ’-’ (1-64 chars)
结果:{ value }: null when not set
secrets.set
权限:secrets
参数:
key:as above
value:string (max 1024 chars); at most 32 secrets per plugin (status 413)
结果:{}
secrets.delete
权限:secrets
参数:
key:as above
结果:{ deleted }
待办与每日笔记
todos.list
权限:todos:read
参数:
date?:YYYY-MM-DD (since 2); missing means today
结果:{ date, todos, scheduled, activeTodoId }. A past date reads that day’s archive ({ …, archived: true }; status 404 when nothing was archived for it); a later date gives the todos scheduled for it in ‘scheduled’.
todos.days
权限:todos:read
参数:
from:YYYY-MM-DD
to:YYYY-MM-DD
结果:{ days: [{ date, total, completed, hasNote, archived }] }: today and every archived day from ‘from’ to ‘to’ (inclusive), oldest first.
todos.add
权限:todos:write
参数:
title:string
date?:YYYY-MM-DD; later than today goes to the ‘later’ list
结果:The new todo.
todos.update
权限:todos:write
参数:
id:string
title?:string
completed?:boolean
结果:The changed todo.
todos.remove
权限:todos:write
参数:
id:string
结果:{ id }
note.get
权限:notes:read
参数:
date?:YYYY-MM-DD (since 2); missing means today
结果:{ date, note }. A past date reads that day’s archived note ({ …, archived: true }; status 404 when nothing was archived); a later date is status 400.
source?:string; omitted clears every source of the plugin
结果:{ cleared }
剪贴板、消息与文件中转
clipboard.history
权限:clipboard:read(敏感)
参数:
limit?:1-50, default 20
结果:{ items: [{ id, text (max 4000 chars), truncated, copiedAt, favorite }] }: text items only, newest first. Status 409 while clipboard history is off.
messages.list
权限:messages:read(敏感)
参数:无
结果:{ items: [{ source: qq | wechat | qqMail, id, sender, preview, receivedAt, unread? }] }, newest first, from the sources the user switched on. WeChat entries have sender and preview null (only the tray flash is known); qqMail preview is the subject, never the body.
{}; call clipboard.history. Only while clipboard history is on.
messages.received
messages:read
One entry as in messages.list: { source, id, sender, preview, receivedAt, unread? }
media.changed
media:read
Same as media.nowPlaying; sent when the track, player or play state changes (checked every 2 s while subscribed), not for the position.
shelf.changed
shelf:read
{ count }: the file shelf changed (by the user or a plugin); call shelf.list for the entries.
system.locked
不需要
{}: the user locked the session (Win+L, or away).
system.unlocked
不需要
{}: the session was unlocked.
system.suspended
不需要
{}: the computer is going to sleep; there is little time left to save.
system.resumed
不需要
{}: the computer woke up.
system.idle
不需要
{ idleSeconds }: no keyboard or mouse input for 5 minutes (checked every 5 s); sent once until input comes back.
system.active
不需要
{}: input again after system.idle.
岛屿发给插件的通知
initialize
{ apiVersion, capabilities (since 2), activationEvent (since 2: onStartup, onCommand:, onView:, onEvent:, onSchedule:, onStartupFinished, onUri, or onSettingsChanged when the user changed the settings of an on-demand plugin that was not running), appVersion, pluginId, dataDir, permissions (those usable now: the manifest’s permissions plus the optional ones the user allowed), optionalPermissions (since 2), settings, experimentalApis (only for a development-mode plugin whose manifest lists experimentalApis: those the island has) }
command
{ id, args? }: a button on the plugin page or the command’s keybinding (since 2) sends { id }; an entry of the todo right-click menu (contributes.menus “todo/context”, since 2) sends { id, args: { todoId } }; of the clipboard, file shelf or message right-click menu (“clipboard/context”, “shelf/context”, “message/context”) sends { id, args: { item } }, the entry as clipboard.history, shelf.list or messages.list show it
settings.changed
{ settings }
event
{ name, payload }; at most one per event name every 200 ms, carrying the latest payload, except messages.received, which delivers every message (up to 50 per 200 ms). Subscriptions end when the process exits, and events that need a sensitive permission stop as soon as the user revokes it.
notification.action
{ id }: the user clicked that button of an island.notify message
uri
{ uri, path, query }: a focusd://plugin//? link was opened (only with activationEvents onUri, after the user allowed it on the island; query is still percent-encoded)
view.visible
{ viewId, visible }: the page was opened or closed; send updates while it is visible
view.action
{ viewId, actionId, itemId?, checked? }: the user clicked an action or an item, or a check box (checked)
view.submit
{ viewId, values }: the user submitted the form
view.search
{ viewId, query }: the user typed in the list’s search box (only if the model asks for searchMode remote)
webview.message
{ viewId, message }: the plugin’s webview page called acquireFuyuApi().postMessage(message) (max 256 KB)
shutdown
{}
插件发给岛屿的通知
log
{ message }
错误码
代码
含义
-32700
Not valid JSON.
-32600
Not a valid JSON-RPC 2.0 message.
-32601
Unknown method.
-32001
The plugin was not given the permission the method needs.
-32000
The island answered with an error; data.status is 400 bad params, 404 not found, 413 too large, 409 the feature is switched off, 429 too many requests, 500 the host could not do it (e.g. a file or the Credential Manager failed), 504 no answer in time.