App Interface: Plugin methods to interact with user notes

linkPlugin API Reference Documentation: App interface

The app interface provides the means of interacting with the application. It is passed to all plugin action functions as the first argument. All app interface functions should be considered asynchronous, returning a Promise that will either resolve to the result, or reject if there is an error.


linkRetrieving App Interface as a markdown document for LLMs

When referencing this page via an LLM, it can be faster to retrieve the page via its pure markdown version: https://public.amplenote.com/C8TUXf394zsvrGn8NwXgoJ7f.md


linkapp.addNoteTag

Add a tag to a note.

Arguments

noteHandle identifying the note to add the tag to

String text of the tag to add - note that this will be normalized to conform to allowed tag names (lowercase, dashes), if it is not a valid tag name

Returns

boolean indicating whether the tag was added. In some cases, shared tags cannot be added to notes - and this will return false.

Throws

If the given tag argument is not a string

{
async noteOption(app, noteUUID) {
const added = await app.addNoteTag({ uuid: noteUUID }, "some-tag");
await app.alert(added ? "Tag added" : "Failed to add tag");
}
}


linkapp.addTaskDomainNote

Ensure the specified note is included in the specified task domain. If the note is already included in the task domain by virtue of a tag the note has, the note will be included directly in the task domain such that removing the tag from the note will leave it in the task domain.

Arguments

String task domain UUID, which can be obtained by calling app.getTaskDomains

noteHandle identifying the note to add to the task domain. Will not create a new note if the note handle describes a note that does not yet exist.

Returns

boolean indicating whether the note was added to the task domain (or is already included in the task domain). A return value of false generally indicates an issue with the note handle (e.g. it identifies a note that doesn't exist, is malformed, etc).

Throws

If the given task domain UUID does not correspond to any task domain

{
async noteOption(app, noteUUID) {
const taskDomains = await app.getTaskDomains();
const taskDomain = taskDomains[0];
const added = await app.addTaskDomainNote(taskDomain.uuid, { uuid: noteUUID });
await app.alert(added ? "Note added to first task domain" : "Failed to add note");
}
}


linkapp.alert

Show the user a message. The name of the plugin is shown in the title of the dialog. Similar to app.prompt, except that this doesn't offer inputs, and instead offers "actions", which are buttons the user can pick at the bottom of the notification.

Arguments

message the String to show the user. Use "\n" to output new lines. Unicode characters are supported. Markdown is not (yet).

(optional) object describing additional options, containing any of the following properties:

actions optional Array of action objects that will be added as buttons on the dialog. Each action object can have the following properties:

icon optional String name of a Material Icon to show on the button

label the String text to show on the button

value optional value (of any basic JS type) that will be returned when the action is triggered, instead of the index in the actions array

preface a String to show before the main message

primaryAction an object describing the presentation of the rightmost button on the dialog (the "DONE" button), with the following properties:

icon optional String name of a Material Icon to show on the button

label the String text to show on the button

scrollToEnd a boolean indicating whether the message shown to the user should be scrolled down so the end is visible, if it is long enough that the alert dialog has a scrollbar

Returns

null if the user dismisses the dialog

-1 if the user presses the "DONE" button (or the primaryAction button, if supplied)

If options.actions is provided:

The integer index corresponding to the action the user selected, or - if the selected action includes a value key, the value associated with the value key.


{
noteOption(app, noteUUID) {
app.alert("This is an alert");
}
}



{
async noteOption(app, noteUUID) {
const actionIndex = await app.alert("This is an alert", {
actions: [
{ icon: "post_add", label: "Insert in note" }
]
});
 
if (actionIndex === 0) {
// "Insert in note"
}
}
}



linkapp.attachNoteMedia

Upload a media file, associating it with a the specified note. This function uploads the file directly, so the user must be online for it to work, and it may take a long time, depending on the size of the media and connectivity.

Arguments

noteHandle describing the note to attach the media to

dataURL a data URL describing the media file data

Returns

String URL of uploaded media

Throws

If the media file is too large, or otherwise not allowed

If there are network errors that prevent upload

{
async insertText(app) {
const noteHandle = { uuid: app.context.noteUUID };
 
const response = await fetch("https://source.unsplash.com/featured/300x200");
const blob = await response.blob();
const dataURL = await this._dataURLFromBlob(blob);
 
const fileURL = await app.attachNoteMedia(noteHandle, dataURL);
 
app.context.replaceSelection(`![](${ fileURL })`);
return null;
},
 
_dataURLFromBlob(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
 
reader.onload = event => {
resolve(event.target.result);
};
 
reader.onerror = function(event) {
reader.abort();
reject(event.target.error);
};
 
reader.readAsDataURL(blob);
});
}
}


linkapp.context

Provides details about where the plugin action was invoked, and allows for interaction at that location.


linkapp.context.embedArgs

Only present in onEmbedCall action functions - the array of arguments used when rendering the embed. See Inline embeds with parameters


linkapp.context.isPublicNote

When a plugin embed is rendering in a published note, this will be true, only when being viewed from the public url, i.e. https://public.amplenote.com/TOKEN


linkapp.context.link

link object describing properties of the link the plugin action was invoked from, e.g. for insertText or replaceText actions. Will be undefined if the plugin action was not invoked from a context where the selection is in a link.


linkapp.context.noteUUID

The String UUID of the note the plugin action was invoked from. This will include the note UUID that a task is in when invoking an action (e.g. insertText or replaceText) in the tasks view, or other editable task lists.


linkapp.context.pluginUUID

The String UUID of the plugin itself - this is the note UUID of the plugin note.


linkapp.context.replaceSelection

Replaces the selection with markdown content. This function will not be present for plugin actions that are not invoked with a user selection/cursor placed in a note - i.e. it is only defined for insertText and replaceText plugin actions. Note that the user can navigate away from a note while a plugin action is executing, in which case, calling this function is not guaranteed to do anything.

Arguments

String of markdown content to replace the selection with

Returns

boolean indicating if the given markdown content replaced the selection. Returns false if the selection has been completely removed from the note, or if the markdown content can't be inserted at the current location (e.g. a table in a task).

Throws

If the context in which the selection existed is no longer available, e.g. the note is completely closed

{
async insertText(app) {
const replacedSelection = await app.context.replaceSelection("**new content**");
if (replacedSelection) {
return null;
} else {
return "plain text"; // Fall back in cases where the markdown content wouldn't be valid at the selection position
}
}
}


linkapp.context.selectionContent

When invoked from an editor context, the markdown representation of the content that is currently selected.


linkapp.context.taskUUID

If the plugin action was invoked from a position in a task, this will be the String UUID of the task in question.

{
insertText(app) {
return app.context.taskUUID || "not in a task";
}
}


linkapp.context.updateImage

If the plugin action was invoked on an image (i.e. imageOption actions), can be called to update image properties.

{
async imageOption(app, image) {
await app.context.updateImage({ caption: "and " + image.caption.toString() });
}
}


linkapp.context.updateLink

If the plugin action was invoked in a link, can be called to update link properties.

{
async replaceText(app) {
if (app.context.updateLink) {
const newDescription = (app.context.link.description || "") + "\nmore";
app.context.updateLink({ description: newDescription });
}
 
return null;
}
}


linkapp.context.url

A URL representing the current location in the app. Can be passed to app.navigate to return to the same location.


linkapp.createNote

Create a new note, optionally specifying a name and/or tags to apply.

Arguments

name - optional String name to give the new note

tags - optional Array of String tag names to apply to the new note

Returns

uuid of the newly created note. This is typically a local-prefixed UUID that may change once persisted to the remote servers, but can continue to be used on the same client to identify the note. Calling app.findNote with this uuid will return a noteHandle with a non-local-prefixed UUID if the note has since completed persistence.

{
async noteOption(app, noteUUID) {
const uuid = await app.createNote("some new note", [ "some-tag" ]);
app.alert(uuid);
}
}


linkapp.deleteNote

Delete a note. Users can restore deleted notes for 30 days after they are first deleted.

Arguments

noteHandle describing the note to delete

Returns

Boolean indicating whether the note described by the noteHandle exists such that it can be deleted.

{
async noteOption(app, noteUUID) {
await app.deleteNote({ uuid: noteUUID });
}
}


linkapp.evaluateExpression

Evaluates a string expression, using the same logic used to evaluate in-editor {expressions}.

Arguments

string the expression to evaluate

Returns

string or number result of the expression, or null if the expression is not valid

{
async appOption(app) {
const result = await app.evaluateExpression("tomorrow");
await app.alert("Result: " + result);
}
}


linkapp.filterNotes

Find noteHandles for all notes matching a set of filter criteria.

Arguments

(optional) object describing filter parameters, containing any of the following properties:

group - filter group to apply. This corresponds to the group= query string parameter when viewing https://www.amplenote.com/notes and filtering on a specific group or set of groups. Multiple groups can be specified with a , separator.

query - String fuzzy search term to filter matching notes on. Note that this is not full-text search, and matches the behavior of note suggestion UI that matches on note names.

tag - tag filter to apply. This corresponds to the tag= query string parameter when viewing https://www.amplenote.com/notes and filtering on a specific tag or set of tags. Multiple tags can be specified with a , separator - matching notes must have all specified tags. A tag prefixed with ^ will only match notes that do not have the tag.

Examples

{ tag: "daily-jots" }

{ tag: "daily-jots,todo" } - matches notes that have the daily-jots tag and the todo tag.

{ tag: "daily-jots,^todo/next" } - matches notes that have the daily-jots tag and do not have the todo/next tag.

Returns

An array of noteHandles for all notes that match the filter parameters.

{
async insertText(app) {
const noteHandles = await app.filterNotes({ tag: "daily-jots" });
return `note count: ${ noteHandles.length }`;
}
}


linkapp.findNote

Returns a noteHandle identifying a note, with additional note metadata attributes populated, if the note is extant and not marked as deleted. In addition to verifying whether a note exists, this can be used to fill in some additional details for a note, e.g. if the plugin only has a noteUUID it can call this to get the name and tags applied to the note.

Arguments

noteHandle identifying the note to find, considering the following attributes:

uuid the UUID identifying a specific note - if provided, the other attributes will be ignored.

name String name of the note to find. If uuid is not provided, this must be supplied.

tags optional Array of tag filter Strings that the note must match, in addition to the name. Each array entry can be the name of a tag e.g. [ "some-tag" ] or can include a negation operator to only match notes that don't have that tag, e.g. [ "^not-this-tag" ]

Returns

noteHandle of the note, or null if the note does not exist or has been marked as deleted

{
async noteOption(app, noteUUID) {
const noteHandle = await app.findNote({ uuid: noteUUID });
app.alert(noteHandle.name);
}
}


linkapp.getAttachmentURL

Given the UUID of an attachment, returns a temporary URL that can be used to access the attachment. The client must be online for this function to succeed.

Arguments

String attachment UUID identifying the attachment

Returns

String temporary URL that can be used to access the attachment content

{
async noteOption(app, noteUUID) {
const attachments = await app.getNoteAttachments({ uuid: noteUUID });
if (attachments.length > 0) {
const attachmentURL = await app.getAttachmentURL(attachments[0].uuid);
await app.alert("URL: " + attachmentURL);
} else {
await app.alert("Note doesn't have any attachments");
}
}
}


linkExample: reading attachment content

Note that the web environment plugin code executes in requires a server to respond with CORS headers, and the attachments server does not add these headers for the plugin code origin. The attachments server address is allowed through a plugin CORS proxy that adds the appropriate headers, so it can be used to fetch attachment data.

{
async noteOption(app, noteUUID) {
const attachments = await app.getNoteAttachments({ uuid: noteUUID });
if (attachments.length === 0) {
await app.alert("Note doesn't have any attachments");
return;
}
 
const attachmentURL = await app.getAttachmentURL(attachments[0].uuid);
 
const proxyURL = new URL("https://plugins.amplenote.com/cors-proxy");
proxyURL.searchParams.set("apiurl", attachmentURL);
 
const response = await fetch(proxyURL);
const attachmentContent = await response.text();
 
await app.alert("Attachment text content: " + attachmentContent);
}
}


linkapp.getMoodRatings

Arguments

integer unix timestamp, only ratings left on or after this time will be included in the results

(optional) integer unix timestamp, only ratings left before this time will be included in the results

Returns

Array of moodRating objects

{
async appOption(app) {
const from = Math.floor(Date.now() / 1000) - (60 * 60 * 24); // 1 day ago
const moodRatings = await app.getMoodRatings(from);
await alert("Mood ratings: " + JSON.stringify(moodRatings));
}
}


linkapp.getNoteAttachments

Returns a list of attachments in the given note. Only attachments that are currently referenced in the note will be returned - if an attachment is uploaded to a note then deleted from the note or moved to a different note, it will not be included in the resulting list.

Arguments

noteHandle identifying the note to list attachments for

Returns

Array of attachment objects, or null if the note handle did not identify an existing note

{
async noteOption(app, noteUUID) {
const attachments = await app.getNoteAttachments({ uuid: noteUUID });
await app.alert(`${ attachments.length } attachments`);
}
}


linkapp.getNoteBacklinkContents

Get the content of backlinks - including surrounding context, as would be shown in the backlinks section of a note - from a specific source note to a specific target note.

Arguments

target noteHandle identifying the note being linked to

source noteHandle identifying the note that contains the link(s) to the target note

Returns

Array of markdown strings, one for each link in the source note that references the target note, including relevant note content context

{
async noteOption(app, noteUUID) {
const targetNoteHandle = { uuid: noteUUID };
const sourceNoteHandles = await app.getNoteBacklinks(targetNoteHandle);
if (sourceNoteHandles.length > 0) {
const sourceNoteHandle = sourceNoteHandles[0];
const backlinkContents = await app.getNoteBacklinkContents(targetNoteHandle, sourceNoteHandle);
await app.alert(backlinkContents.join("\n\n"));
} else {
await app.alert("Note has no backlinks");
}
}
}


linkapp.getNoteBacklinks

Returns the list of notes that link to the specified note.

Arguments

noteHandle identifying the note

Returns

Array of noteHandles identifying the notes that have links to the specified note

{
async noteOption(app, noteUUID) {
let count = 0;
for await (const referencingNoteHandle of app.getNoteBacklinks({ uuid: noteUUID })) {
await app.alert("referencingNoteHandle: " + JSON.stringify(referencingNoteHandle));
count++;
}
await app.alert("count: " + count);
}
}


linkapp.getNoteContent

Get the content of a note, as markdown.

Arguments

noteHandle identifying the note

Returns

The content of the note, as markdown.

{
async noteOption(app, noteUUID) {
const markdown = await app.getNoteContent({ uuid: noteUUID });
app.alert(markdown);
}
}


linkapp.getNoteImages

Get all the inline images in a note (does not include images in Rich Footnotes).

Arguments

noteHandle identifying the note

Returns

Array of image objects

{
async noteOption(app, noteUUID) {
const images = await app.getNoteImages({ uuid: noteUUID });
await app.alert("image count: " + images.length);
}
}


linkapp.getNotePublicURL

Get a public URL for the note, if it has been published. Note that this call requires internet connectivity.

Arguments

noteHandle identifying the note

Returns

String URL for the published note, or null if the note is not published

Throws

If a request to the server fails, e.g. if the client is offline

{
async noteOption(app, noteUUID) {
const publicURL = await app.getNotePublicURL({ uuid: noteUUID });
await app.alert("public URL: " + (publicURL || "none"));
}
}


linkapp.getNoteSections

Gets a list of the sections in a note. Sections are areas of the note delimited by either a heading or a horizontal rule. Sections are identified by the heading (if any) that opens the section, and when relevant, an index to disambiguate between multiple sections with matching headings.

Arguments

noteHandle identifying the note

Returns

An Array of the sections the note is comprised of

{
async noteOption(app, noteUUID) {
const sections = await app.getNoteSections({ uuid: noteUUID });
await app.alert("Section count: " + sections);
}
}


linkapp.getNoteSettings

Gets settings specific to a note that are not included in noteHandle metadata, generally related to note styling and secondary displays.

Arguments

noteHandle identifying the note

Returns

null, if the noteHandle does not resolve to a note; otherwise, an Object with the following possible keys:

backgroundColor a String representing the hex color used for the background of the note

bannerImageURL the String URL of an image used as a banner for the note

maxOpenTasks an Integer indicating the maximum number of open tasks the user wishes to have in the note

{
async noteOption(app, noteUUID) {
const settings = await app.getNoteSettings({ uuid: noteUUID });
await app.alert("Settings: " + JSON.stringify(settings));
}
}


linkapp.getNoteTasks

Returns the tasks that are present in the specified note.

Arguments

noteHandle identifying the note to get tasks from. If the note handle identifies a note that does not yet exist, the note will not be created.

options object, with the following optional properties:

includeDone - boolean indicating whether completed and dismissed tasks in the note should be returned in addition to the un-done tasks. Defaults to false.

Returns

Array of task objects

{
async noteOption(app, noteUUID) {
const tasks = await app.getNoteTasks({ uuid: noteUUID });
app.alert(`Note has ${ tasks.length } tasks`);
}
}


linkapp.getNoteURL

Returns a full URL for the specified note. This URL can be used to link to the note (and will be detected as a note link in Amplenote editors/views), and can be used to open the note via app.navigate.

Arguments

noteHandleidentifying the note to get the URL of. If the note handle is for a note that does not yet exist, the note will be created.

Returns

String URL of the note.

{
async noteOption(app, noteUUID) {
const noteURL = await app.getNoteURL({ uuid: noteUUID });
app.alert("note URL: " + noteURL);
}
}


linkapp.getTask

Get the details of a single task.

Arguments

UUID String identifying the task

Returns

task object, or null if no task with the given UUID exists

{
async noteOption(app, noteUUID) {
const taskUUID = "e6adcbcb-04dc-4fbd-857e-dbf63a253e7e";
const task = await app.getTask(taskUUID);
app.alert(JSON.stringify(task));
}
}


linkapp.getTaskDomains

Get the list of configured Task Domains for the user.

Arguments

None

Returns

Array of task domains, each entry an object with the following properties:

name the String display name of the Task Domain

notes an Array of noteHandles, for each note in the Task Domain. This includes notes that are part of the Task Domain due to the tags applied to the note, notes that have been individually specified to be part of the Task Domain, and - for legacy Task Domains - potentially all notes.

uuid the String identifier that uniquely identifies the Task Domain


{
appOption: async function(app) {
const taskDomains = await app.getTaskDomains();
 
const descriptions = taskDomains.map(({ name, notes }) => {
return `${ name } - ${ notes.length } notes`);
});
app.alert(descriptions.join("\n"));
},
}


linkapp.getTaskDomainTasks

Gets the list of tasks that belong to the given task domain. Note that this includes tasks that are not scheduled (on the calendar).

Arguments

String task domain UUID

Returns

Array of task objects describing the tasks in the task domain


Note that this function can return a large amount of data, so it's highly recommended to use an async iterator to reduce the potential for performance impact.

{
async appOption(app) {
const taskDomains = await app.getTaskDomains();
const taskDomainUUID = taskDomains[0].uuid;
 
for await (const task of app.getTaskDomainTasks(taskDomainUUID)) {
console.log("task: " + task.uuid);
}
}
}


linkapp.insertNoteContent

Inserts content into a note.

Arguments

noteHandle identifying the note to insert the text into

content: String of markdown-formatted content to insert

(optional) object of additional options, with the following properties:

atEnd boolean indicating that content should be inserted at the end of the note. Defaults to false.

Returns

Nothing

Throws

If markdown content is over 100k characters

If the target note is readonly

{
noteOption(app, noteUUID) {
app.insertNoteContent({ uuid: noteUUID }, "this is some **bold** text");
}
}


linkapp.insertTask

Inserts a new task at the beginning of a note. See also: note.insertTask.

Arguments

noteHandle identifying the note to insert the task into

task object, with the following attributes (all are optional):

content: String of markdown-formatted content to use in the task

hideUntil: Number a unix timestamp (seconds) to use for the "Hide until" time

startAt: Number a unix timestamp (seconds) to use for the "Start at" time

Returns

The UUID of the newly created task

Throws

If the provided content is not valid in a task (e.g. - a bullet list item)

If note is readonly/locked

{
async noteOption(app, noteUUID) {
const taskUUID = await app.insertTask({ uuid: noteUUID }, { text: "this is a task" });
app.alert(taskUUID);
}
}

link

linkapp.navigate

Opens the app to the location corresponding tot he given Amplenote app URL. Amplenote app URLs start with https://www.amplenote.com/notes. Examples:

Jots area: "https://www.amplenote.com/notes/jots"

Notes area: "https://www.amplenote.com/notes"

Notes list filtered to a tag: "https://www.amplenote.com/notes?tag=some-tag"

Jots area on a specific tag: https://www.amplenote.com/notes/jots?tag=some-tag

A specific note: "https://www.amplenote.com/notes/NOTE_UUID" (replacing NOTE_UUID with a specific note's UUID).


Arguments

url an Amplenote URL string

Returns

true if the given url was a valid Amplenote URL and was navigated to, false otherwise

{
noteOption(app) {
app.navigate("https://www.amplenote.com/notes/jots");
}
}


linkapp.notes

The notes object provides an alternative - and simpler - way to interact with specific notes. Depending on the purpose, it may be preferable than the noteHandle-based functions available on the main app interface. Functions on the notes object return Note interface objects. As with noteHandles, a note interface object may represent a note that does not (yet) exist. Calling any note interface function that requires an extant note will create the note first, if it doesn't already exist.


linkapp.notes.create

Create a new note. This is an alternative interface to app.createNote.

Arguments

name the String to use as the new note's name

tags an Array of String tag names to apply to the new note

Returns

Note interface object for the newly created note

{
async noteOption(app, noteUUID) {
const note = await app.notes.create("some new note", [ "some-tag" ]);
app.alert(note.uuid);
}
}


linkapp.notes.dailyJot

Gets a note interface for the daily jot note on the day corresponding to the given timestamp.

Arguments

timestamp unix timestamp Number (seconds) indicating any time on the day the daily jot note should be for

Returns

Note interface object for the daily jot note

{
async noteOption(app, noteUUID) {
const tomorrowTimestamp = Math.floor(Date.now() / 1000) + 60 * 60 * 24;
const note = await app.notes.dailyJot(tomorrowTimestamp);
app.alert(note.name);
}
}


linkapp.notes.filter

Find noteHandles for all notes matching a set of filter criteria. This is an alternative interface to app.filterNotes.

Arguments

(optional) object describing filter parameters, containing any of the following properties:

group - filter group to apply. This corresponds to the group= query string parameter when viewing https://www.amplenote.com/notes and filtering on a specific group or set of groups. Multiple groups can be specified with a , separator.

Examples

{ group: "archived" }

{ group: "taskList,archived" }

tag - tag filter to apply. This corresponds to the tag= query string parameter when viewing https://www.amplenote.com/notes and filtering on a specific tag or set of tags. Multiple tags can be specified with a , separator - matching notes must have all specified tags. A tag prefixed with ^ will only match notes that do not have the tag.

Examples

{ tag: "daily-jots" }

{ tag: "daily-jots,todo" } - matches notes that have the daily-jots tag and the todo tag.

{ tag: "daily-jots,^todo/next" } - matches notes that have the daily-jots tag and do not have the todo/next tag.

Returns

An array of noteHandles for all notes that match the filter parameters.

{
async insertText(app) {
const noteHandles = await app.notes.filter({ tag: "daily-jots" });
return `note count: ${ noteHandles.length }`;
}
}


linkapp.notes.find

Builds an object that allows you to more concisely call app.* functions for a specific note.

Arguments

Either one of

uuid the String UUID identifying the note

noteHandle identifying the note

Returns

Note interface object for the note, or null if the note does not exist or has been marked as deleted

{
async noteOption(app, noteUUID) {
const note = await app.notes.find(noteUUID);
app.alert(note.name);
}
}


{
async noteOption(app) {
const note = await app.notes.find({ name: "some note" });
app.alert(note ? "Note exists" : "Note doesn't exist");
}
}


linkapp.openEmbed

Adds a section to the sidebar (or drawer menu on the mobile app), allowing the user to open a full screen embed. The section is only added to the local client instance, and is not synchronized across clients. Updates to the embed arguments (e.g. by calling app.context.updateEmbedArgs) will be persisted, until the user manually removes the plugin section.

Arguments:

Anything. Will be passed to renderEmbed, after the app argument.

Returns

nothing

({
async appOption(app) {
await app.openEmbed();
 
// The embed section isn't navigated to when calling openEmbed, but can be navigated to with:
await app.navigate("https://www.amplenote.com/notes/plugins/" + app.context.pluginUUID);
},
 
async renderEmbed(app) {
// Render embed content as desired
},
})






linkapp.openSidebarEmbed

Opens an embed for the plugin (see renderEmbed) in the Peek Viewer, if it is available for the user. If the plugin has already opened a sidebar embed, the existing sidebar embed will be re-rendered by calling renderEmbed again with the latest passed args.

Arguments

Number or object - if a Number, the aspect ratio to use for embed. Embeds are fully isolated from the hosting application, so they can't be sized dynamically based on the content of the embed (content in the embed is not accessible to the hosting application). Instead, an aspect ratio is supplied here that will be maintained in the embed.
If an object, in the shape of:

aspectRatio - Number aspect ratio, as described above

id string identifying the specific sidebar embed. Multiple sidebar embeds can be opened by the same plugin by supplying unique id values for each one

...args arguments that will be passed to the plugin's renderEmbed action

Returns

Boolean indicating whether the embed could be opened. Will return false in the mobile app, where there is no Peek Viewer.

{
appOption(app) {
app.openSidebarEmbed(1, "one", [ 2, 3, 4 ]);
},
renderEmbed(app, ...args) {
return `<b>got:</b> ${ JSON.stringify(args) }`;
},
}


Invoking from quick open (via appOption):



Rendered in Peek Viewer, after selecting plugin in quick open:



See renderEmbed for examples of communicating between an embed and the plugin that rendered it.


linkapp.prompt

Show the user a message and input fields - defaulting to a single text input - receiving the user-selected/user-entered value(s). Similar to app.alert, except that this allows options to be presented in a dialog, and does not allow multiple buttons at the bottom of the window, like app.alert does.

Arguments

message String to show the user. New lines can be inserted with \n. Unicode characters are supported in output. Markdown isn't supported...yet.

(optional) object describing additional options, containing any of the following properties:

inputs an optional Array of input objects describing the input fields to show. If not provided, a single text input field will be shown (equivalent to inputs: [ { type: "text" } ]).

input object, with the following properties:

label a String to use as a label for the input. Examples: checkbox, select, and text

limit a Number to use as the maximum number of tags that can be selected in a type: "tags" input. If omitted, defaults to 1

options Array of options to use in a type: "select" drop-down input or type: "radio" input each option an object with the following properties:

label the String to show as a label on the input field

value the value corresponding to the option. Will be returned as the result (verbatim) when the user selects the option.

image a String URL of an image to show with the option. Only used in type: "radio" inputs.

placeholder a String to use as a placeholder value for a type: "text" input

type String one of the following values:

"checkbox" a check box field

"date" a calendar date selection field

"note" a field to select a single note from the user's notes list

"radio" a set of radio buttons to select one option from. When specified, the options property should also be provided.

"secureText" a short text field that masks the displayed characters like a password field.

"select" a drop-down select field. When specified, the options property should also be provided.

"string" a single line text input field

"tags" an auto-complete field for the user's tags, in which a single tag can be selected by default, or more can be selected by providing a limit value.

"text" a multi-line text area field

value the initial value for the input. If the user does not change the input, submitting the prompt will use this value. Note that the value must match the value field in one of the options for type: "radio" and type: "select" inputs, or it will be ignored.

actions optional Array of action objects that will be added as buttons on the dialog. Each action object can have the following properties:

icon optional String name of a Material Icon to show on the button

label the String text to show on the button

value optional value (of any basic JS type) that will be returned when the action is triggered, instead of the index in the actions array

Returns

null if the user selected "Cancel", or otherwise closed the dialog without pressing "Submit"

If no inputs or actions options are provided

The String text the user entered

If a single inputs option and no actions are provided, one of:

The String text the user entered for a type: "text" or type: "string" input

The String tag text the user selected for a type: "tags" input. If multiple tags are selected, they will be joined with a , to produce a single string.

The Integer value corresponding to the unix timestamp (seconds) that the user selected for a type: "date" input, or null if no day was selected.

The value corresponding to the option.value the user selected in a type: "radio" input

The Bool value corresponding to the user's selection for a type: "checkbox" input

The noteHandle of the selected note for a type: "note" input

The value corresponding to the value field of the selected type: "select" option

If multiple inputs are provided, an Array of values corresponding to value selected for each input (in the same order they were specified), followed by a single entry corresponding to the actions entry that the user selected, or -1 if the user pressed the default "Submit" button.

{
async insertText(app) {
let result = await app.prompt("Enter text");
return result;
}
}




{
async noteOption(app, noteUUID) {
const result = await app.prompt("This is the message", {
inputs: [
{ label: "This is the label", placeholder: "This is the placeholder", type: "text" },
{ label: "This is the label", type: "checkbox" },
{ label: "This is the label", type: "select", options: [ { label: "something", value: 1 }, { label: "other", value: 2 } ] },
{ label: "This is the label", type: "radio", options: [ { label: "something", value: 1 }, { label: "other", value: 2 } ] },
]
});
 
if (result) {
const [ textResult, checkboxResult, selectResult ] = result;
 
} else {
// User canceled
}
}
}




{
async noteOption(app, noteUUID) {
const result = await app.prompt("This is the message", {
actions: [
{ label: "Alternative action", value: "alternative" },
{ label: "Another action" },
],
inputs: [
{ label: "This is the label", type: "text" },
{ label: "This is the label", type: "checkbox" },
]
});
 
if (result) {
const [ textResult, checkboxResult, actionResult ] = result; // `result` will be `null` if user presses "Cancel" button or dismisses popup
 
// actionResult === "alternative" // if "Alternative action" was pressed
// actionResult === 1 // if "Another action" was pressed (the index of this action in the `actions` array)
// actionResult === -1 // If the default "Submit" button was pressed
 
} else {
// User canceled
}
}
}



linkapp.publishNote

Arguments

noteHandle describing the note to publish. Must be a remotely-persisted note.

Returns

The String URL of the published note, or null if the note could not be published. Note publishing requires an Unlimited or Founder subscription, and an active connection to the internet.

Notes

If the note is already published by the current user, an existing URL will be returned instead of creating a new URL

{
async noteOption(app, noteUUID) {
const url = await app.publishNote({ uuid: noteUUID });
await app.alert("Public URL: " + url);
}
}


linkapp.removeNoteTag

Removes a tag from a note.

Arguments

noteHandle identifying the note to add the tag to

String text of the tag to remove

Returns

boolean indicating whether the tag was removed. In some cases, shared tags cannot be removed from notes - and this will return false. Note that this will return true even if the note did not have the tag - only a failure to remove a tag will result in false.

Throws

If the given tag argument is not a string

{
async noteOption(app, noteUUID) {
const removed = await app.removeNoteTag({ uuid: noteUUID }, "some-tag");
app.alert(added ? "Tag removed" : "Failed to remove tag");
}
}


linkapp.replaceNoteContent

Replace the entire content of a note with new content, or replace the content of a single section of the note (see app.getNoteSectionsfor discussion of sections).

Arguments

noteHandle describing the note to replace content in

Markdown content String of new content

(optional) object of additional options, supporting the following properties

section object describing the section of the note to replace content in. For sections that start with a heading, the heading will not be replaced, only the content of the section.

includeCompletedTasks boolean indicating whether completed tasks should be replaced in addition to the main note content

includeHiddenTasks boolean indicating whether hidden tasks should be replaced in addition to the main note content

Returns

bool indicating whether the replacement was performed. Note that the only failure state for a replacement is when a section is specified and that section is not found in the note.

Throws

If markdown content is over 100k characters

If the target note is readonly

{
async noteOption(app, noteUUID) {
const newContent = "**new content**";
await app.replaceNoteContent({ uuid: noteUUID }, content);
}
}


With a section:

{
async noteOption(app, noteUUID) {
const newContent = "**new content**";
const section = { heading: { text: "Heading of Section to Replace" }};
await app.replaceNoteContent({ uuid: noteUUID }, content, { section });
}
}


linkapp.saveFile

Save a file.

Arguments

The Blob/ File object describing the content of the file

String filename to use for the file

Returns

A promise that resolves when the request to save the file has been sent. Note that the user may see a prompt to accept/name/save the file, in which case this will resolve as soon as the request has been displayed to the user - it does not wait for the user to actually save the file.

{
async noteOption(app) {
const file = new Blob([ "some text" ], { type: "text/plain" });
await app.saveFile(file, "test.txt");
}
}


linkapp.searchNotes

Search note content. This matches in-app "full search" functionality.

Arguments

query - string term to search for in note content

Returns

An array of noteHandles for all notes with content matching the query, ordered with best matches first

{
async insertText(app) {
const noteHandles = await app.searchNotes("something");
return `note count: ${ noteHandles.length }`;
}
}

link

linkapp.setNoteName

Sets a new name for the given note.

Arguments

noteHandle describing the note to set the name of

String new name for the note

Returns

Boolean indicating whether the name could be changed. Generally, the only failure case is if the note handle doesn't identify an extant note.

Throws

If the name argument is not a string

{
async noteOption(app, noteUUID) {
const noteHandle = await app.findNote({ uuid: noteUUID }); // findNote returns a note handle with the `name` attribute included
await app.setNoteName(noteHandle, noteHandle.name + " more");
}
}


linkapp.setNoteSetting

Set the value of a note setting, as returned by app.getNoteSettings.

Arguments

noteHandle describing an extant note to set a setting for

key String setting name, which currently allows the following settings:

"backgroundColor", with the value as a String representing the hex color used for the background of the note

"maxOpenTasks", with the value as an Integer indicating the maximum number of open tasks the user wishes to have in the note

value - the value to set for the setting; type varies depending on the setting key

Returns

boolean indicating whether the setting was updated

Throws

If the key or value arguments are not valid

{
async noteOption(app, noteUUID) {
await app.setNoteSetting({ uuid: noteUUID }, "backgroundColor", "#ff0000");
}
} p


linkapp.setSetting

Update the value of a single setting. The value will be synchronized to all of the user's devices. Note that the updated value is not guaranteed to be updated in app.settings before the next invocation of a plugin function (check or run).

Arguments

String setting name to update, or add

String new value for the setting. Any non-string values (with the exception of null) will be converted to strings.

Returns

Nothing

{
async appOption(app) {
const count = parseInt(app.settings["counter"] || "0", 10);
await app.setSetting("counter", count + 1);
app.alert("new value: " + count);
}
}


linkapp.settings

An object containing the user-configured settings for the plugin. All values will be strings.


{
insertText(app) {
return app.settings["Some setting"];
}
}


This will insert the string the user has entered for "Some setting", assuming the plugin metadata table includes:

setting

Some setting


linkapp.unpublishNote

Arguments

noteHandle describing the note to publish. Must be a remotely-persisted note.

Returns

boolean indicating whether the note is (now) not published

Throws

If network connectivity is not available

{
async noteOption(app, noteUUID) {
await app.unpublishNote(noteUUID);
}
}


linkapp.updateNoteImage

Update an image in a specific note.

Arguments

noteHandle identifying the note to update an image in

image identifying the image to update - only the index and src keys are necessary

object describing the updates to the image, which can contain the properties described in by image, with the exception of the index property

Returns

boolean indicating whether the image could be updated

Throws

If the given markdown is not valid in an image caption


{
async noteOption(app, noteUUID) {
const noteHandle = { uuid: noteUUID };
const images = await app.getNoteImages(noteHandle);
 
for (let i = 0; i < images.length; i++) {
const image = images[i];
await app.updateNoteImage(noteHandle, image, { caption: "**new caption**" });
}
}
}


linkapp.updateTask

Update the properties or content of a single task.

Arguments

String UUID identifying the task

object containing (optional) updates to apply to the task. All properties listed for a task are supported, except the uuid

Returns

boolean indicating whether the task could be updated. If the given task UUID doesn't correspond to any existing task, will return false

{
async insertText(app) {
const taskUUID = app.context.taskUUID;
if (!taskUUID) return null; // Cursor is not in a task
 
await app.updateTask(taskUUID, { completedAt: Math.floor(Date.now() / 1000) });
 
return "";
}
}


linkapp.writeClipboardData

Write to the clipboard. The plugin code execution environment can prevent use of clipboard APIs in some browsers, so this app function is provided for full cross-platform support.

Arguments

String data to copy to the clipboard. For non-string mime types, should be base64 encoded data.

Optional String mime type of data, defaults to "text/plain". The following mime types are allowed:

"text/plain" - data argument should be the text to copy to the clipboard

"image/png" - data argument should be base64 encoded image data

Returns

Nothing

Throws

If an unsupported mime type argument is supplied

If base64 data is not validly base64 encoded

{
async noteOption(app, noteUUID) {
await app.writeClipboardData(noteUUID);
await app.alert("Note UUID copied to clipboard");
}
}