UXP Manifest v5
Manifest v5 gives developers access to a new plugin permissions model and WebViews in modal dialogs. Using the full manifest v5 feature set requires PS 23.3.0 or higher. (UXP 6.0 or higher)
Upgrade your plugin to use the latest manifest feature set by changing the
manifestVersion
element.
Copied to your clipboard"manifestVersion": 5
Example manifest
Copied to your clipboard1{2 "manifestVersion": 5,3 "id": "YOUR_ID_HERE",4 "name": "Name of your plugin",5 "version": "1.0.0",6 "main": "index.html",7 "host": {8 "app": "PS",9 "minVersion": "23.3.0"10 },11 "entrypoints": [12 {13 "type": "command",14 "id": "commandFn",15 "label": {16 "default": "Show A Dialog"17 }18 },19 {20 "type": "panel",21 "id": "panelName",22 "label": {23 "default": "Panel Name"24 },25 "minimumSize": {"width": 230, "height": 200},26 "maximumSize": {"width": 2000, "height": 2000},27 "preferredDockedSize": {"width": 230, "height": 300},28 "preferredFloatingSize": {"width": 230, "height": 300},29 "icons": [30 {"width":23,"height":23,"path":"icons/dark.png","scale":[1,2],"theme":["darkest","dark","medium"]},31 {"width":23,"height":23,"path":"icons/light.png","scale":[1,2],"theme":["lightest","light"]}32 ]33 }34 ],35 "icons": [36 { "width": 23, "height": 23, "path": "icons/icon_D.png", "scale": [ 1, 2 ], "theme": [ "dark", "darkest" ], "species": [ "generic" ] },37 { "width": 23, "height": 23, "path": "icons/icon_N.png", "scale": [ 1, 2 ], "theme": [ "lightest", "light" ], "species": [ "generic" ] }38 ],39 "requiredPermissions": {40 "network": {41 "domains": [42 "https://adobe.com",43 ]44 },45 "clipboard": "readAndWrite",46 "webview": {47 "allow": "yes",48 "domains": [ "https://*.adobe.com", "https://*.google.com"]49 },50 "launchProcess": {51 "schemes":52 [ "https", "slack"],53 "extensions":54 [ ".xd", ".psd" ]55 },56 },57}
Changes to top-level metadata
Starting from changes to top-level metadata, here are some keys that changed with the v5 upgrade. Read manifest v4 to learn more about each key/value field.
Key path | Type | Description | Change |
---|---|---|---|
version
|
string
|
Version number of your plugin in
x.y.z
format.
|
Plugins can specify semver format with no warnings.
Specify at least one number and the minor and/or patch will be autofilled with zeroes. |
requiredPermissions
|
object
|
Declare
plugin permissions
.
|
New in v5.
|
entrypoints
|
EntryPointDefinition[]
|
Describes the entries your plugin adds to the
Plugins
menu and plugin panel.
|
v5 changes in next section.
|
Updates to Entrypoints methods
With manifest v4:
- Promise-based methods were not supported for entrypoint methods.
- No timeouts for entrypoints methods.
-
All panel entrypoints have only one argument
event
which containsnode
,panel
,eventName
andPanelID
.
Manifest v5 brings additional lifecycle events to better manage your plugin and more flexibility in specifying the initial view and location of plugins' panels:
-
UXP honors promises returned by (most) entrypoint methods.
-
Plugin entrypoints
: Promise support is enabled for plugin
destroy
. -
Panel entrypoints
: Promise support is enabled for panel
create
,show
,destroy
,hide
. -
Currently, panel
show
is tied to plugincreate
, and panelhide
is tied to plugindestroy
.
-
Plugin entrypoints
: Promise support is enabled for plugin
- Entrypoint methods have a timeout of 300 milliseconds
-
Panel entrypoints have
rootNode
as first argument anddata
as second argument forshow
andhide
.
entrypoints.setup() using promises
Copied to your clipboard1import { entrypoints } from "uxp";2entrypoints.setup({3 plugin: {4 create() {5 console.log("Plugin has been loaded, plugin.create has been triggered.");6 },7 destroy() {8 return new Promise(function (resolve, reject) {9 console.log("Plugin has been loaded, plugin.create has been triggered.");10 resolve();11 });12 }13 },14 panels: {15 panelA: {16 create(rootNode) {17 return new Promise(function (resolve, reject) {18 console.log("PanelA is created, panelA.create has been triggered.");19 resolve();20 });21 },22 show(rootNode, data) {23 return new Promise(function (resolve, reject) {24 console.log("PanelA is about to be displayed, panelA.show has been triggered with data ", data);25 resolve();26 });27 },28 hide(rootNode, data) {29 return new Promise(function (resolve, reject) {30 console.log("PanelA is about to be hidden, panelA.hide has been triggered with data ", data);31 resolve();32 });33 },34 destroy(rootNode) {35 return new Promise(function (resolve, reject) {36 console.log("PanelA is about to be destroyed, panelA.destroy has been triggered.");37 resolve();38 });39 },40 invokeMenu(menuId) {41 return new Promise(function (resolve, reject) {42 console.log("A menu item on PanelA has been invoked, panelA.invokeMenu has been triggered with menu id ", menuId);43 resolve();44 });45 },46 menuItems: [...]47 },48 "panelB": {..}49 },50 commands: {51 "command1": {52 run() {..},53 cancel() {..}54 },55 "command2": function(){..}56 }57});
Plugin Permissions
Plugins using Manifest v5 will enjoy the enhancements in security with the introduction of new permissions model. Users will be asked for their consent when your plugin attempts to use
openExternal
,
openPath
, and
sp-link
/anchor tags. For everything else, consent is given at install time.
Starting with v5, any permissions not explicitly declared in the manifest are not granted by default.
Network
In order for our plugin to use the network, you must define domains that your plugin will access. You can do this by adding the network object to the requiredPermissions section of the manifest.
Copied to your clipboard1{2 "requiredPermissions": {3 "network": {4 "domains": [5 "https://source.unsplash.com",6 ]7 }8 }9}
Copied to your clipboard<img src='https://source.unsplash.com/random'>
Clipboard
To grant read and/or write access to the system clipboard, declare it in
requiredPermissions
.
clipboard
accepts:
-
readAndWrite
for read/write access -
read
for read-only access.
Copied to your clipboard1{2 "requiredPermissions": {3 "clipboard": "readAndWrite"4 }5}
Copied to your clipboard1const clipboard = navigator.clipboard;2const dataTransferProviders = {3 'text/plain': 'Sample text'4};5clipboard.writeText(dataTransferProviders).then(6 (result) => {...},7 (error) => {...}8);
Local Filesystem
The
localFileSystem
permission controls access to the user's local file system. If not specified, the plugin has no access to the user's file system other than the default access to
plugin://
,
plugin-temp://
, and
plugin-data://
.
localFileSystem
accepts:
-
request
: Allows the plugin to access the local file system using pickers for opening and saving files. -
plugin
: Allows the plugin to access the plugin's storage only. -
fullAccess
: Allows the plugin to inspect, modify, and delete files to which you have access on all volumes attached to this device. The user will be required to consent before installation or update.
Copied to your clipboard1{2 "requiredPermissions": {3 "localFileSystem": "request"4 }5}
Copied to your clipboard1const fs = require('uxp').storage.localFileSystem;2const file = await fs.getFileForSaving('manifest_demo.txt');3await file.write('Manifest v5 demo');
If
plugin
is not specified for plugin storage, the manifest will default to that setting.
Launch Process
The
launchProcess
permission in the manifest controls the ability to launch applications and open files in other applications.
With manifest v5, the
launchProcess
permission must be declared to use
openExternal
or
openPath
.
Copied to your clipboard1"permissions": {2 "launchProcess": {3 // allows launching files with specified URI schemes4 "schemes":5 [ "https", "slack", "adbxd" ],6 // allows opening files with the specified file extensions7 "extensions":8 [ ".pdf", ".xd", ".psd" ],9 },10}
Both
openPath
and
openExternal
rely on this permission set, and upon either function call, the user will get a runtime consent dialog. Only after they agree will the API call execute.
Plugin communication
If enabled, the plugin can communicate with other installed plugins. Defaults to
false
.
Copied to your clipboard1"permissions": {2 "ipc": {3 "enablePluginCommunication": true4 }5}
Copied to your clipboard1const { pluginManager } = require("uxp");2// find the Alchemist plugin in the loaded plugins3const alchemistPlugin = Array.from(pluginManager.plugins).find(plugin => plugin.id==="2bcdb900");4//What commands and panels are available?5const alchemistCommands = Array.from(alchemistPlugin.manifest.commands, command => command.commandId); // result: ["resetStateFn"]6const alchemistPanels = Array.from(alchemistPlugin.manifest.panels, command => command.panelId); // result: ["inspector"]7// Show the inspector panel; note that panels can only be made visible -- you can't ask to hide the panel8alchemistPlugin.showPanel("inspector");9// Reset Alchemists state... but be sure you want to do this!10alchemistPlugin.invokeCommand("resetStateFn");
WebViews
WebViews are available with UXP 6.0, and need to be configured in your plugin's manifest (v5 required).
In your
manifest.json
:
Copied to your clipboard1{2 "manifestVersion": 5,3 "requiredPermissions": {4 "webview": {5 "allow": "yes",6 // domains --> string[] | "all"7 "domains": [ "https://*.adobe.com", "https://*.google.com"],8 }9 }10}
Then in your plugin's code:
Copied to your clipboard1<dialog>2 <webview id="webview" width="100%" height="360px" src="https://www.adobe.com"></webview>3</dialog>
Copied to your clipboarddocument.querySelector("dialog").showModal();